Additional fixes for https://bugs.eclipse.org/bugs/show_bug.cgi?id=392500
Recursive Generics can me mutually recursive, Multi-bounded and wildcard-scoped.
Conflicts:
core/src/test/java/org/eclipse/gemini/blueprint/blueprint/container/TypeFactoryTest.java
Fix compilation errors
diff --git a/core/src/main/java/org/eclipse/gemini/blueprint/blueprint/container/TypeFactory.java b/core/src/main/java/org/eclipse/gemini/blueprint/blueprint/container/TypeFactory.java
index aded1e0..336201a 100644
--- a/core/src/main/java/org/eclipse/gemini/blueprint/blueprint/container/TypeFactory.java
+++ b/core/src/main/java/org/eclipse/gemini/blueprint/blueprint/container/TypeFactory.java
@@ -20,6 +20,7 @@
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -104,13 +105,13 @@
TypeVariable[] tvs = type.getType().getTypeParameters();
arguments = new ArrayList<ReifiedType>(tvs.length);
for (@SuppressWarnings("rawtypes") TypeVariable tv : tvs) {
- ReifiedType rType = getReifiedType(tv);
+ ReifiedType rType = getReifiedType(tv, null);
arguments.add(rType);
}
return arguments;
}
- private static ReifiedType getReifiedType(Type targetType) {
+ private static ReifiedType getReifiedType(Type targetType, Collection<Type> variableTypes) {
if (targetType instanceof Class) {
if (Object.class.equals(targetType)) {
return OBJECT;
@@ -119,7 +120,7 @@
}
if (targetType instanceof ParameterizedType) {
Type ata = ((ParameterizedType) targetType).getActualTypeArguments()[0];
- return getReifiedType(ata);
+ return getReifiedType(ata, variableTypes);
}
if (targetType instanceof WildcardType) {
WildcardType wt = (WildcardType) targetType;
@@ -127,29 +128,37 @@
if (ObjectUtils.isEmpty(lowerBounds)) {
// there's always an upper bound (Object)
Type upperBound = wt.getUpperBounds()[0];
- return getReifiedType(upperBound);
+ return getReifiedType(upperBound, variableTypes);
}
- return getReifiedType(lowerBounds[0]);
+ return getReifiedType(lowerBounds[0], variableTypes);
}
if (targetType instanceof TypeVariable) {
TypeVariable<?> typeVariable = (TypeVariable<?>) targetType;
+ if (variableTypes == null) {
+ variableTypes = new ArrayList<Type>(2);
+ } else if (variableTypes.contains(targetType)) {
+ //Looped around on itself via a recursive Generics definition
+ return OBJECT;
+ }
+ variableTypes.add(targetType);
Type[] bounds = typeVariable.getBounds();
- Type boundZero = bounds[0];
- if (bounds.length == 1 && boundZero instanceof ParameterizedType) {
- Type ata = ((ParameterizedType) boundZero).getActualTypeArguments()[0];
- if (targetType.equals(ata)) {
- //recursive declaration like <T extends Comparable<T>>
- return OBJECT;
+ for (Type bound : bounds) {
+ if (bound instanceof ParameterizedType) {
+ Type ata = ((ParameterizedType) bound).getActualTypeArguments()[0];
+ if (ata instanceof TypeVariable) {
+ variableTypes.add(ata);
+ }
+ return getReifiedType(bound, variableTypes);
}
}
- return getReifiedType(boundZero);
+ return getReifiedType(bounds[0], variableTypes);
}
if (targetType instanceof GenericArrayType) {
- return getReifiedType(((GenericArrayType) targetType).getGenericComponentType());
+ return getReifiedType(((GenericArrayType) targetType).getGenericComponentType(), variableTypes);
}
throw new IllegalArgumentException("Unknown type " + targetType.getClass());
diff --git a/core/src/test/java/org/eclipse/gemini/blueprint/blueprint/container/TypeFactoryTest.java b/core/src/test/java/org/eclipse/gemini/blueprint/blueprint/container/TypeFactoryTest.java
index b762de0..e56745d 100644
--- a/core/src/test/java/org/eclipse/gemini/blueprint/blueprint/container/TypeFactoryTest.java
+++ b/core/src/test/java/org/eclipse/gemini/blueprint/blueprint/container/TypeFactoryTest.java
@@ -54,8 +54,8 @@
public void typedList(LinkedList<Point> arg) {
}
- public void array(Integer[] arg) {
- }
+ public void array(Integer[] arg) {
+ }
public void extendsList(LinkedList<? extends Shape> arg) {
}
@@ -94,23 +94,28 @@
private static class RecursiveGenericType<T extends Comparable<T>> {
}
- private static class SingleAndRecursiveGenericType<S extends String, T extends Comparable<T>> {
+ private static class SingleAndRecursiveGenericType<S extends String, T extends Comparable<S>> {
}
private static class MultipleRecursiveGenericType<T extends Comparable<T>, U extends T> {
}
-
+
private static class MutuallyRecursiveGenericType<T extends Comparable<U>, U extends Comparable<T>> {
- // Must T always equal U?
+ // Must T always equal U?
}
-
+
private static class ComplexRecursiveGenericType<T extends Comparable<? super T>> {
}
-
+
private static class MultiBoundedRecursiveGenericType<T extends Comparable<T> & Cloneable> {
- // Cloneable could be replaced by any interface
+ // Cloneable could be replaced by any interface
}
-
+
+ private static interface Ice {}
+ private static interface Juice {}
+ private static class A<T extends Ice & Juice> {}
+ private static class B<T extends Juice & Ice> {}
+
@Test
public void testJdk4Classes() throws Exception {
ReifiedType tp = getReifiedTypeFor("rawList");
@@ -118,29 +123,29 @@
assertEquals(List.class, tp.getRawClass());
}
- @Test
+ @Test
public void testPrimitive() throws Exception {
ReifiedType tp = getReifiedTypeFor("primitive");
assertEquals(0, tp.size());
assertEquals(Integer.class, tp.getRawClass());
}
- @Test
+ @Test
public void testArray() throws Exception {
ReifiedType tp = getReifiedTypeFor("array");
assertEquals(1, tp.size());
assertEquals(Integer[].class, tp.getRawClass());
- assertEquals(Integer.class, tp.getActualTypeArgument(0).getRawClass());
+ assertEquals(Integer.class, tp.getActualTypeArgument(0).getRawClass());
}
- @Test
+ @Test
public void testInteger() throws Exception {
ReifiedType tp = getReifiedTypeFor("integer");
assertEquals(0, tp.size());
assertEquals(Integer.class, tp.getRawClass());
}
- @Test
+ @Test
public void testTypedObjectList() throws Exception {
ReifiedType tp = getReifiedTypeFor("typedList");
assertEquals(1, tp.size());
@@ -148,7 +153,7 @@
assertEquals(Point.class, tp.getActualTypeArgument(0).getRawClass());
}
- @Test
+ @Test
public void testExtendsList() throws Exception {
ReifiedType tp = getReifiedTypeFor("extendsList");
assertEquals(1, tp.size());
@@ -156,7 +161,7 @@
assertEquals(Shape.class, tp.getActualTypeArgument(0).getRawClass());
}
- @Test
+ @Test
public void testSuperList() throws Exception {
ReifiedType tp = getReifiedTypeFor("superList");
assertEquals(1, tp.size());
@@ -164,7 +169,7 @@
assertEquals(Shape.class, tp.getActualTypeArgument(0).getRawClass());
}
- @Test
+ @Test
public void testTypedMap() throws Exception {
ReifiedType tp = getReifiedTypeFor("typedMap");
assertEquals(2, tp.size());
@@ -173,7 +178,7 @@
assertEquals(Double.class, tp.getActualTypeArgument(1).getRawClass());
}
- @Test
+ @Test
public void testPointMap() throws Exception {
ReifiedType tp = getReifiedTypeFor("pointMap");
assertEquals(2, tp.size());
@@ -182,59 +187,59 @@
assertEquals(Point.class, tp.getActualTypeArgument(1).getRawClass());
}
- // Since spring 3.1 the TypeDescriptor no longer contains any reference to the MethodParameter
- // class, we we are unable to get the ParameterizedType of a method parameter.
- // So all actual type arguments just become Object.class.
+ // Since spring 3.1 the TypeDescriptor no longer contains any reference to the MethodParameter
+ // class, we we are unable to get the ParameterizedType of a method parameter.
+ // So all actual type arguments just become Object.class.
@Test
- @Ignore
- public void testTypedReference() throws Exception {
+ @Ignore
+ public void testTypedReference() throws Exception {
ReifiedType tp = getReifiedTypeFor("typedReference");
assertEquals(AtomicReference.class, tp.getRawClass());
- assertEquals(1, tp.size());
- assertEquals(Boolean.class, tp.getActualTypeArgument(0).getRawClass());
+ assertEquals(1, tp.size());
+ assertEquals(Boolean.class, tp.getActualTypeArgument(0).getRawClass());
}
- @Test
+ @Test
public void testObjectTypedReference() throws Exception {
ReifiedType tp = getReifiedTypeFor("objectTypedReference");
assertEquals(AtomicReference.class, tp.getRawClass());
- assertEquals(1, tp.size());
- assertEquals(Object.class, tp.getActualTypeArgument(0).getRawClass());
+ assertEquals(1, tp.size());
+ assertEquals(Object.class, tp.getActualTypeArgument(0).getRawClass());
}
- @Test
+ @Test
public void testWildcardReference() throws Exception {
ReifiedType tp = getReifiedTypeFor("wildcardReference");
assertEquals(AtomicReference.class, tp.getRawClass());
- assertEquals(1, tp.size());
- assertEquals(Object.class, tp.getActualTypeArgument(0).getRawClass());
+ assertEquals(1, tp.size());
+ assertEquals(Object.class, tp.getActualTypeArgument(0).getRawClass());
}
- // Since spring 3.1 the TypeDescriptor no longer contains any reference to the MethodParameter
- // class, we we are unable to get the ParameterizedType of a method parameter.
- // So all actual type arguments just become Object.class.
- @Test
- @Ignore
+ // Since spring 3.1 the TypeDescriptor no longer contains any reference to the MethodParameter
+ // class, we we are unable to get the ParameterizedType of a method parameter.
+ // So all actual type arguments just become Object.class.
+ @Test
+ @Ignore
public void testSuperReference() throws Exception {
ReifiedType tp = getReifiedTypeFor("superTypedReference");
assertEquals(AtomicReference.class, tp.getRawClass());
- assertEquals(1, tp.size());
- assertEquals(Properties.class, tp.getActualTypeArgument(0).getRawClass());
+ assertEquals(1, tp.size());
+ assertEquals(Properties.class, tp.getActualTypeArgument(0).getRawClass());
}
- // Since spring 3.1 the TypeDescriptor no longer contains any reference to the MethodParameter
- // class, we we are unable to get the ParameterizedType of a method parameter.
- // So all actual type arguments just come Object.class.
- @Test
- @Ignore
+ // Since spring 3.1 the TypeDescriptor no longer contains any reference to the MethodParameter
+ // class, we we are unable to get the ParameterizedType of a method parameter.
+ // So all actual type arguments just come Object.class.
+ @Test
+ @Ignore
public void testExtendsReference() throws Exception {
ReifiedType tp = getReifiedTypeFor("extendsTypedReference");
assertEquals(AtomicReference.class, tp.getRawClass());
- assertEquals(1, tp.size());
- assertEquals(Properties.class, tp.getActualTypeArgument(0).getRawClass());
+ assertEquals(1, tp.size());
+ assertEquals(Properties.class, tp.getActualTypeArgument(0).getRawClass());
}
- @Test
+ @Test
public void testTypeVariable() throws Exception {
ReifiedType tp = getReifiedTypeFor("typeVariable");
assertEquals(1, tp.size());
@@ -242,7 +247,7 @@
assertEquals(Object.class, tp.getActualTypeArgument(0).getRawClass());
}
- @Test
+ @Test
public void testCustomDictionary() throws Exception {
ReifiedType tp = getReifiedTypeFor("customDictionary");
assertEquals(2, tp.size());
@@ -251,41 +256,50 @@
assertEquals(Object.class, tp.getActualTypeArgument(1).getRawClass());
}
- @Test
+ @Test
public void testUnknownType() throws Exception {
ReifiedType type = TypeFactory.getType(TypeDescriptor.forObject(null));
assertEquals(Object.class, type.getRawClass());
}
- @Test
+ @Test
public void testRecursiveGenericType() throws Exception {
assertNotNull(TypeFactory.getType(TypeDescriptor.valueOf(RecursiveGenericType.class)));
}
- @Test
- public void testSingleAndRecursiveGenericType() throws Exception {
- assertNotNull(TypeFactory.getType(TypeDescriptor.valueOf(SingleAndRecursiveGenericType.class)));
- }
+ @Test
+ public void testSingleAndRecursiveGenericType() throws Exception {
+ assertNotNull(TypeFactory.getType(TypeDescriptor.valueOf(SingleAndRecursiveGenericType.class)));
+ }
- @Test
- public void testMultipleRecursiveGenericType() throws Exception {
- assertNotNull(TypeFactory.getType(TypeDescriptor.valueOf(MultipleRecursiveGenericType.class)));
- }
+ @Test
+ public void testMultipleRecursiveGenericType() throws Exception {
+ assertNotNull(TypeFactory.getType(TypeDescriptor.valueOf(MultipleRecursiveGenericType.class)));
+ }
- @Test
- public void testMutuallyRecursiveGenericType() throws Exception {
- assertNotNull(TypeFactory.getType(TypeDescriptor.valueOf(MutuallyRecursiveGenericType.class)));
- }
+ @Test
+ public void testMutuallyRecursiveGenericType() throws Exception {
+ assertNotNull(TypeFactory.getType(TypeDescriptor.valueOf(MutuallyRecursiveGenericType.class)));
+ }
- @Test
- public void testComplexRecursiveGenericType() throws Exception {
- assertNotNull(TypeFactory.getType(TypeDescriptor.valueOf(ComplexRecursiveGenericType.class)));
- }
+ @Test
+ public void testComplexRecursiveGenericType() throws Exception {
+ assertNotNull(TypeFactory.getType(TypeDescriptor.valueOf(ComplexRecursiveGenericType.class)));
+ }
- @Test
- public void testMultiBoundedRecursiveGenericType() throws Exception {
- assertNotNull(TypeFactory.getType(TypeDescriptor.valueOf(MultiBoundedRecursiveGenericType.class)));
- }
+ @Test
+ public void testMultiBoundedRecursiveGenericType() throws Exception {
+ assertNotNull(TypeFactory.getType(TypeDescriptor.valueOf(MultiBoundedRecursiveGenericType.class)));
+ }
+
+ @Test
+ public void testMultiBoundedGenericType() throws Exception {
+ ReifiedType reifiedA = TypeFactory.getType(TypeDescriptor.valueOf(A.class));
+ assertNotNull(reifiedA);
+ ReifiedType reifiedB = TypeFactory.getType(TypeDescriptor.valueOf(B.class));
+ assertNotNull(reifiedB);
+ }
+
private ReifiedType getReifiedTypeFor(String methodName) {
Method mt = BeanUtils.findDeclaredMethodWithMinimalParameters(TestSet.class, methodName);