-
Notifications
You must be signed in to change notification settings - Fork 286
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
WELD-1111 Inheritance of member-level metadata for generic types - mi…
…ssing substitution of actual type arguments
- Loading branch information
Showing
12 changed files
with
283 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
impl/src/main/java/org/jboss/weld/util/reflection/GenericArrayTypeImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package org.jboss.weld.util.reflection; | ||
|
||
import java.lang.reflect.GenericArrayType; | ||
import java.lang.reflect.Type; | ||
|
||
/** | ||
* @author Marko Luksa | ||
*/ | ||
class GenericArrayTypeImpl implements GenericArrayType { | ||
|
||
private Type genericComponentType; | ||
|
||
GenericArrayTypeImpl(Type genericComponentType) { | ||
this.genericComponentType = genericComponentType; | ||
} | ||
|
||
public Type getGenericComponentType() { | ||
return genericComponentType; | ||
} | ||
} |
98 changes: 98 additions & 0 deletions
98
impl/src/main/java/org/jboss/weld/util/reflection/TypeVariableResolver.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
package org.jboss.weld.util.reflection; | ||
|
||
import javax.enterprise.inject.spi.Bean; | ||
import java.lang.reflect.GenericArrayType; | ||
import java.lang.reflect.ParameterizedType; | ||
import java.lang.reflect.Type; | ||
import java.lang.reflect.TypeVariable; | ||
import java.util.HashMap; | ||
|
||
/** | ||
* @author Marko Luksa | ||
*/ | ||
public class TypeVariableResolver { | ||
|
||
private Class beanClass; | ||
private HashMap<TypeVariable,Type> resolvedVariables; | ||
|
||
public TypeVariableResolver(Class beanClass) { | ||
if (beanClass == null) { | ||
throw new IllegalArgumentException("beanClass should not be null"); | ||
} | ||
this.beanClass = beanClass; | ||
} | ||
|
||
public static Type resolveVariables(Bean bean, Type type) { | ||
if (bean == null) { | ||
// bean is null when we're dealing with an InjectionTarget created through BeanManager.createInjectionTarget() | ||
// we can't resolve variables since we're missing critical info, thus we simply return the original type for now | ||
return type; | ||
} | ||
if (bean.getBeanClass() == null) { | ||
throw new IllegalArgumentException("Bean " + bean + " has null beanClass!"); | ||
} | ||
return new TypeVariableResolver(bean.getBeanClass()).resolveVariablesInType(type); | ||
} | ||
|
||
public Type resolveVariablesInType(Type type) { | ||
if (type instanceof ParameterizedType) { | ||
ParameterizedType parameterizedType = (ParameterizedType) type; | ||
return new ParameterizedTypeImpl( | ||
parameterizedType.getRawType(), | ||
resolveVariablesInTypes(parameterizedType.getActualTypeArguments()), | ||
parameterizedType.getOwnerType()); | ||
} else if (type instanceof TypeVariable) { | ||
TypeVariable typeVariable = (TypeVariable) type; | ||
return resolveTypeVariable(typeVariable); | ||
} else if (type instanceof GenericArrayType) { | ||
GenericArrayType genericArrayType = (GenericArrayType) type; | ||
return new GenericArrayTypeImpl(resolveVariablesInType(genericArrayType.getGenericComponentType())); | ||
} else { | ||
return type; | ||
} | ||
} | ||
|
||
private Type[] resolveVariablesInTypes(Type[] types) { | ||
Type[] resolvedTypes = new Type[types.length]; | ||
for (int i = 0; i < types.length; i++) { | ||
resolvedTypes[i] = resolveVariablesInType(types[i]); | ||
} | ||
return resolvedTypes; | ||
} | ||
|
||
private Type resolveTypeVariable(TypeVariable typeVariable) { | ||
if (resolvedVariables == null) { | ||
resolvedVariables = new HashMap<TypeVariable, Type>(); | ||
fillResolvedVariablesMap(beanClass); | ||
} | ||
return resolve(typeVariable); // instead of resolving every time, we could also resolve all entries immediately after filling map | ||
} | ||
|
||
private void fillResolvedVariablesMap(Class beanClass) { | ||
Type genericSuperclass = beanClass.getGenericSuperclass(); | ||
if (genericSuperclass instanceof ParameterizedType) { | ||
ParameterizedType parameterizedSuperClassType = (ParameterizedType) genericSuperclass; | ||
|
||
Type[] actualTypeArguments = parameterizedSuperClassType.getActualTypeArguments(); | ||
TypeVariable[] typeParameters = beanClass.getSuperclass().getTypeParameters(); | ||
for (int i = 0; i < typeParameters.length; i++) { | ||
resolvedVariables.put(typeParameters[i], actualTypeArguments[i]); | ||
} | ||
} | ||
|
||
if (beanClass.getSuperclass() != null) { | ||
fillResolvedVariablesMap(beanClass.getSuperclass()); | ||
} | ||
} | ||
|
||
private Type resolve(Type type) { | ||
if (type instanceof TypeVariable) { | ||
TypeVariable typeVariable = (TypeVariable) type; | ||
if (resolvedVariables.containsKey(typeVariable)) { | ||
return resolve(resolvedVariables.get(typeVariable)); | ||
} | ||
} | ||
return type; | ||
} | ||
|
||
} |
27 changes: 27 additions & 0 deletions
27
tests-arquillian/src/test/java/org/jboss/weld/tests/unit/reflection/inheritance/A.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package org.jboss.weld.tests.unit.reflection.inheritance; | ||
|
||
/** | ||
* | ||
*/ | ||
public class A<E1, E2> { | ||
|
||
private Faz faz; | ||
|
||
private E1 e1; | ||
|
||
private Foo<E1> foo1; | ||
|
||
private Foo<E2> foo2; | ||
|
||
private Foo<String> stringFoo; | ||
|
||
private Foo<Foo<String>> stringFooFoo; | ||
|
||
private Foo<Foo<E1>> variableFooFoo; | ||
|
||
private Foo<String>[] stringFooArray; | ||
|
||
private E1[] variableArray; | ||
|
||
private Foo<E1>[] foo1Array; | ||
} |
9 changes: 9 additions & 0 deletions
9
tests-arquillian/src/test/java/org/jboss/weld/tests/unit/reflection/inheritance/B.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package org.jboss.weld.tests.unit.reflection.inheritance; | ||
|
||
/** | ||
* | ||
*/ | ||
public class B<T,U> extends A<T, Double> { | ||
|
||
private Foo<U> foo3; | ||
} |
8 changes: 8 additions & 0 deletions
8
...lian/src/test/java/org/jboss/weld/tests/unit/reflection/inheritance/BOfIntegerString.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package org.jboss.weld.tests.unit.reflection.inheritance; | ||
|
||
/** | ||
* | ||
*/ | ||
public class BOfIntegerString extends B<Integer, String> { | ||
|
||
} |
9 changes: 9 additions & 0 deletions
9
tests-arquillian/src/test/java/org/jboss/weld/tests/unit/reflection/inheritance/C.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package org.jboss.weld.tests.unit.reflection.inheritance; | ||
|
||
/** | ||
* | ||
*/ | ||
public class C<U,T> extends B<T, U> { // note the flipped arguments! | ||
|
||
private Foo<U> foo4; | ||
} |
8 changes: 8 additions & 0 deletions
8
...quillian/src/test/java/org/jboss/weld/tests/unit/reflection/inheritance/COfByteShort.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package org.jboss.weld.tests.unit.reflection.inheritance; | ||
|
||
/** | ||
* | ||
*/ | ||
public class COfByteShort extends C<Byte, Short> { | ||
|
||
} |
7 changes: 7 additions & 0 deletions
7
tests-arquillian/src/test/java/org/jboss/weld/tests/unit/reflection/inheritance/Faz.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package org.jboss.weld.tests.unit.reflection.inheritance; | ||
|
||
/** | ||
* | ||
*/ | ||
public class Faz { | ||
} |
7 changes: 7 additions & 0 deletions
7
tests-arquillian/src/test/java/org/jboss/weld/tests/unit/reflection/inheritance/Foo.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package org.jboss.weld.tests.unit.reflection.inheritance; | ||
|
||
/** | ||
* | ||
*/ | ||
public class Foo<T> { | ||
} |
83 changes: 83 additions & 0 deletions
83
.../test/java/org/jboss/weld/tests/unit/reflection/inheritance/TypeVariableResolverTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package org.jboss.weld.tests.unit.reflection.inheritance; | ||
|
||
import org.jboss.weld.util.reflection.TypeVariableResolver; | ||
import org.junit.Test; | ||
|
||
import javax.enterprise.util.TypeLiteral; | ||
import java.lang.reflect.Field; | ||
import java.lang.reflect.Type; | ||
|
||
import static junit.framework.Assert.assertEquals; | ||
|
||
/** | ||
* @author <a href="mailto:marko.luksa@gmail.com">Marko Luksa</a> | ||
*/ | ||
public class TypeVariableResolverTest { | ||
|
||
@Test | ||
public void testConcreteType() throws Exception { | ||
assertTypeEquals(new TypeLiteral<Faz>() { }, A.class, A.class.getDeclaredField("faz")); | ||
} | ||
|
||
@Test | ||
public void testParameterizedConcreteType() throws Exception { | ||
assertTypeEquals(new TypeLiteral<Foo<String>>() { }, A.class, A.class.getDeclaredField("stringFoo")); | ||
} | ||
|
||
@Test | ||
public void testNestedParameterizedType() throws Exception { | ||
assertTypeEquals(new TypeLiteral<Foo<Foo<String>>>() { }, A.class, A.class.getDeclaredField("stringFooFoo")); | ||
} | ||
|
||
@Test | ||
public void testNestedParameterizedTypeWithVariable() throws Exception { | ||
assertTypeEquals(new TypeLiteral<Foo<Foo<Integer>>>() { }, BOfIntegerString.class, A.class.getDeclaredField("variableFooFoo")); | ||
} | ||
|
||
@Test | ||
public void testParameterizedTypeWithVariable() throws Exception { | ||
assertTypeEquals(new TypeLiteral<Foo<String>>() { }, BOfIntegerString.class, B.class.getDeclaredField("foo3")); | ||
} | ||
|
||
@Test | ||
public void testSuperSuperClass() throws Exception { | ||
assertTypeEquals(new TypeLiteral<Foo<Integer>>() {}, BOfIntegerString.class, A.class.getDeclaredField("foo1")); | ||
} | ||
|
||
@Test | ||
public void testSuperSuperClassWhereVariableIsDefinedInSuperClass() throws Exception { | ||
assertTypeEquals(new TypeLiteral<Foo<Double>>() {}, BOfIntegerString.class, A.class.getDeclaredField("foo2")); | ||
} | ||
|
||
@Test | ||
public void testStringFooArray() throws Exception { | ||
assertTypeEquals(new TypeLiteral<Foo<String>[]>() {}, BOfIntegerString.class, A.class.getDeclaredField("stringFooArray")); | ||
} | ||
|
||
@Test | ||
public void testVariableArray() throws Exception { | ||
assertTypeEquals(new TypeLiteral<Integer[]>() {}, BOfIntegerString.class, A.class.getDeclaredField("variableArray")); | ||
} | ||
|
||
@Test | ||
public void testArrayWithParameterizedTypeWithVariable() throws Exception { | ||
assertTypeEquals(new TypeLiteral<Foo<Integer>[]>() {}, BOfIntegerString.class, A.class.getDeclaredField("foo1Array")); | ||
} | ||
|
||
@Test | ||
public void testVariable() throws Exception { | ||
assertTypeEquals(new TypeLiteral<Integer>() {}, BOfIntegerString.class, A.class.getDeclaredField("e1")); | ||
} | ||
|
||
@Test | ||
public void testSuperSuperSuperClass() throws Exception { | ||
assertTypeEquals(new TypeLiteral<Foo<Short>>() {}, COfByteShort.class, A.class.getDeclaredField("foo1")); | ||
} | ||
|
||
private void assertTypeEquals(TypeLiteral<?> expectedTypeLiteral, Class beanClass, Field field) { | ||
Type expectedType = expectedTypeLiteral.getType(); | ||
Type type = new TypeVariableResolver(beanClass).resolveVariablesInType(field.getGenericType()); | ||
assertEquals(expectedType, type); | ||
} | ||
|
||
} |