package org.jboss.weld.tests.unit.reflection.util; import java.io.Serializable; import java.io.Writer; import java.lang.reflect.Type; import java.util.Collection; import java.util.List; import javax.enterprise.util.TypeLiteral; import org.junit.Assert; import org.jboss.weld.resolution.AssignabilityRules; import org.jboss.weld.resolution.BeanTypeAssignabilityRules; import org.jboss.weld.util.reflection.Reflections; import org.junit.Test; /** * @author <a href="mailto:marko.luksa@gmail.com">Marko Luksa</a> * @author Jozef Hartinger */ @SuppressWarnings("serial") public class BeanTypeAssignabilityTest { protected AssignabilityRules getRules() { return BeanTypeAssignabilityRules.instance(); } @Test public void testGetRawType() throws Exception { Assert.assertEquals(Foo.class, Reflections.getRawType(new TypeLiteral<Foo<Integer>>() { }.getType())); } @Test public void testGetRawTypeOfArray() throws Exception { Assert.assertEquals(Foo[].class, Reflections.getRawType(new TypeLiteral<Foo<Integer>[]>() { }.getType())); } @Test public void testIntegerFooMatchesItself() throws Exception { Type type = new TypeLiteral<Foo<Integer>>() { }.getType(); Assert.assertTrue("type should match itself", getRules().matches(type, type)); } @Test public void testIntegerFooDoesNotMatchStringFoo() throws Exception { Type type1 = new TypeLiteral<Foo<Integer>>() { }.getType(); Type type2 = new TypeLiteral<Foo<String>>() { }.getType(); Assert.assertFalse("Foo<Integer> should not match Foo<String>", getRules().matches(type1, type2)); } @Test public void testFooMatchesItself() throws Exception { Type type = Foo.class; Assert.assertTrue("type should match itself", getRules().matches(type, type)); } @Test public void testParameterizedArrayDoesNotMatchComponentOfArray() throws Exception { Type arrayType = new TypeLiteral<Foo<String>[]>() { }.getType(); Type componentType = new TypeLiteral<Foo<String>>() { }.getType(); Assert.assertFalse("array type should not match its component type", getRules().matches(arrayType, componentType)); } @Test public void testParameterizedArrayMatches() throws Exception { Type type = new TypeLiteral<Foo<Integer>[]>() { }.getType(); Assert.assertTrue("type should match itself", getRules().matches(type, type)); } @Test public void testArraysDontMatch() throws Exception { Type type1 = new TypeLiteral<Foo<Integer>[]>() { }.getType(); Type type2 = new TypeLiteral<Foo<String>[]>() { }.getType(); Assert.assertFalse("Foo<Integer>[] should not match Foo<String>[]", getRules().matches(type1, type2)); } @Test public void testWildcardFooMatchesStringFoo() throws Exception { Type stringFooType = new TypeLiteral<Foo<String>>() { }.getType(); Type wildcardFooType = new TypeLiteral<Foo<?>>() { }.getType(); Assert.assertTrue("Foo<?> should be assignable from Foo<String>", getRules().matches(wildcardFooType, stringFooType)); } @Test public void testWildcardFooArrayMatchesStringFooArray() throws Exception { Type stringFooArrayType = new TypeLiteral<Foo<String>[]>() { }.getType(); Type wildcardFooArrayType = new TypeLiteral<Foo<?>[]>() { }.getType(); Assert.assertTrue("Foo<?>[] should be assignable from Foo<String>[]", getRules().matches(wildcardFooArrayType, stringFooArrayType)); } @Test public void testStringFooArrayDoesNotMatchWildcardFooArray() throws Exception { Type stringFooArrayType = new TypeLiteral<Foo<String>[]>() { }.getType(); Type wildcardFooArrayType = new TypeLiteral<Foo<?>[]>() { }.getType(); Assert.assertFalse("Foo<String>[] should not be assignable from Foo<?>[]", getRules().matches(stringFooArrayType, wildcardFooArrayType)); } @Test public <E> void testVariableFooMatchesItself() throws Exception { Type type = new TypeLiteral<Foo<E>>() { }.getType(); Assert.assertTrue("Foo<E> should be assignable from Foo<E>", getRules().matches(type, type)); } @Test public <E> void testStringFooMatchesVariableFoo() throws Exception { Type stringFooType = new TypeLiteral<Foo<String>>() { }.getType(); Type variableFooType = new TypeLiteral<Foo<E>>() { }.getType(); Assert.assertTrue("Foo<String> should match Foo<E>", getRules().matches(stringFooType, variableFooType)); } @Test public <E> void testVariableFooArrayMatchesItself() throws Exception { Type type = new TypeLiteral<Foo<E>[]>() { }.getType(); Assert.assertTrue("Foo<E>[] should be assignable from Foo<E>[]", getRules().matches(type, type)); } @Test public void testRawRequiredTypeMatchesParameterizedBeanWithObjectTypeParameter() throws Exception { Assert.assertTrue("Foo<Object> should be assignable to Foo", getRules().matches(Foo.class, new TypeLiteral<Foo<Object>>() { }.getType())); } @Test public <E> void testRawRequiredTypeMatchesParameterizedBeanWithUnboundedVariableTypeParameter() throws Exception { Assert.assertTrue("Foo<E> should be assignable to Foo", getRules().matches(Foo.class, new TypeLiteral<Foo<E>>() { }.getType())); } @Test public <F extends Number> void testParameterizedBeanWithBoundedVariableTypeParameter() throws Exception { Assert.assertFalse("Foo<F extends Number> should not be assignable to Foo", getRules().matches(Foo.class, new TypeLiteral<Foo<F>>() { }.getType())); } @Test public void testArrays() { Assert.assertTrue("int[][] should be assignable to int[][]", getRules().matches(new int[0][].getClass(), new int[0][].getClass())); Assert.assertTrue("Integer[][] should be assignable to Integer[][]", getRules().matches(new Integer[0][].getClass(), new Integer[0][].getClass())); Assert.assertTrue("List<Integer[][]> should be assignable to List<Integer[][]>", getRules().matches(new TypeLiteral<List<Integer[][]>>() {}.getType(), new TypeLiteral<List<Integer[][]>>() {}.getType())); Assert.assertFalse("List<Integer[][]> should not be assignable to List<Number[][]>", getRules().matches(new TypeLiteral<List<Number[][]>>() {}.getType(), new TypeLiteral<List<Integer[][]>>() {}.getType())); } @Test public void testArrayBoxing() { /* * This is not explicitly said in the CDI spec however Java SE does not support array boxing so neither should CDI. */ Assert.assertFalse("Integer[] should not be assignable to int[]", getRules().matches(new int[0].getClass(), new Integer[0].getClass())); Assert.assertFalse("int[] should not be assignable to Integer[]", getRules().matches(new Integer[0].getClass(), new int[0].getClass())); } @Test public <T1 extends Number, T2 extends T1> void testTypeVariableWithTypeVariableBound() { Assert.assertTrue("List<T2 extends T1 extends Number> should be assignable to List<Number>", getRules().matches(new TypeLiteral<List<Number>>() {}.getType(), new TypeLiteral<List<T2>>() {}.getType())); Assert.assertFalse("List<T2 extends T1 extends Number> should not be assignable to List<Runnable>", getRules().matches(new TypeLiteral<List<Runnable>>() {}.getType(), new TypeLiteral<List<T2>>() {}.getType())); Assert.assertTrue("List<T2 extends T1 extends Number> should be assignable to List<T1 extends Number>", getRules().matches(new TypeLiteral<List<T1>>() {}.getType(), new TypeLiteral<List<T2>>() {}.getType())); Assert.assertTrue("List<T1 extends Number> should be assignable to List<T2 extends T1 extends Number>", getRules().matches(new TypeLiteral<List<T2>>() {}.getType(), new TypeLiteral<List<T1>>() {}.getType())); } @Test public <T1 extends Exception, T2 extends T1, T3 extends Exception, T4 extends T3, T5 extends Throwable> void testTypeVariablesWithTypeVariableBounds() { Assert.assertTrue("List<T2 extends T1 extends Exception> should be assignable to List<T4 extends T3 extends Exception>", getRules().matches(new TypeLiteral<List<T4>>() {}.getType(), new TypeLiteral<List<T2>>() {}.getType())); Assert.assertTrue("List<T5 extends Throwable> should be assignable to List<T4 extends T3 extends Exception>", getRules().matches(new TypeLiteral<List<T4>>() {}.getType(), new TypeLiteral<List<T5>>() {}.getType())); Assert.assertFalse("List<T4 extends T3 extends Exception> should not be assignable to List<T5 extends Throwable>", getRules().matches(new TypeLiteral<List<T5>>() {}.getType(), new TypeLiteral<List<T4>>() {}.getType())); } @Test public <T1 extends Number, T2 extends T1> void testWildcardWithTypeVariableBound() { Assert.assertTrue("List<Number> should be assignable to List<? extends T2 extends T1 extends Number>", getRules().matches(new TypeLiteral<List<? extends T2>>() {}.getType(), new TypeLiteral<List<Number>>() {}.getType())); Assert.assertTrue("List<Integer> should be assignable to List<? extends T2 extends T1 extends Number>", getRules().matches(new TypeLiteral<List<? extends T2>>() {}.getType(), new TypeLiteral<List<Integer>>() {}.getType())); Assert.assertFalse("List<Object> should not be assignable to List<? extends T2 extends T1 extends Number>", getRules().matches(new TypeLiteral<List<? extends T2>>() {}.getType(), new TypeLiteral<List<Object>>() {}.getType())); Assert.assertTrue("List<Number> should be assignable to List<? super T2 extends T1 extends Number>", getRules().matches(new TypeLiteral<List<? super T2>>() {}.getType(), new TypeLiteral<List<Number>>() {}.getType())); Assert.assertFalse("List<Integer> should not be assignable to List<? super T2 extends T1 extends Number>", getRules().matches(new TypeLiteral<List<? super T2>>() {}.getType(), new TypeLiteral<List<Integer>>() {}.getType())); Assert.assertTrue("List<Object> should be assignable to List<? super T2 extends T1 extends Number>", getRules().matches(new TypeLiteral<List<? super T2>>() {}.getType(), new TypeLiteral<List<Object>>() {}.getType())); } @Test public <T1 extends List<?> & Appendable, T2 extends Writer & Serializable & Collection<?>, T3 extends T2, T4 extends Appendable & Iterable<?>, T5 extends T4> void testTypeVariableWithMultipleBounds() { Assert.assertTrue("List<T4 extends Appendable & Iterable<?>> should be assignable to List<T1 extends List<?> & Appendable>", getRules().matches(new TypeLiteral<List<T1>>() {}.getType(), new TypeLiteral<List<T4>>() {}.getType())); Assert.assertTrue("List<T4 extends Appendable & Iterable<?>> should be assignable to List<T2 extends Writer & Serializable & Collection<?>>", getRules().matches(new TypeLiteral<List<T2>>() {}.getType(), new TypeLiteral<List<T4>>() {}.getType())); Assert.assertTrue("List<T5 extends T4 extends Appendable & Iterable<?>> should be assignable to List<T3 extends T2 extends Writer & Serializable & Collection<?>>", getRules().matches(new TypeLiteral<List<T3>>() {}.getType(), new TypeLiteral<List<T5>>() {}.getType())); // copy & paste with wildcard Assert.assertTrue("List<T4 extends Appendable & Iterable<?>> should be assignable to List<? extends T1 extends List<?> & Appendable>", getRules().matches(new TypeLiteral<List<? extends T1>>() {}.getType(), new TypeLiteral<List<T4>>() {}.getType())); Assert.assertTrue("List<T4 extends Appendable & Iterable<?>> should be assignable to List<? extends T2 extends Writer & Serializable & Collection<?>>", getRules().matches(new TypeLiteral<List<? extends T2>>() {}.getType(), new TypeLiteral<List<T4>>() {}.getType())); Assert.assertTrue("List<T5 extends T4 extends Appendable & Iterable<?>> should be assignable to List<? extends T3 extends T2 extends Writer & Serializable & List<?>>", getRules().matches(new TypeLiteral<List<? extends T3>>() {}.getType(), new TypeLiteral<List<T5>>() {}.getType())); Assert.assertFalse("List<T1 extends List<?> & Appendable> should not be assignable to List<T4 extends Appendable & Iterable<?>>", getRules().matches(new TypeLiteral<List<T4>>() {}.getType(), new TypeLiteral<List<T1>>() {}.getType())); Assert.assertFalse("List<T1 extends List<?> & Appendable> should not be assignable to List<T2 extends Writer & Serializable & Collection<?>>", getRules().matches(new TypeLiteral<List<T2>>() {}.getType(), new TypeLiteral<List<T1>>() {}.getType())); Assert.assertFalse("List<T2 extends Writer & Serializable & Collection<?>> should not be assignable to List<T4 extends Appendable & Iterable<?>>", getRules().matches(new TypeLiteral<List<T4>>() {}.getType(), new TypeLiteral<List<T2>>() {}.getType())); // neither one type variable has stricter bounds than the other Assert.assertFalse("List<T2 extends Writer & Serializable & Collection<?>> should not be assignable to List<T1 extends List<?> & Appendable>", getRules().matches(new TypeLiteral<List<T1>>() {}.getType(), new TypeLiteral<List<T2>>() {}.getType())); Assert.assertFalse("List<T1 extends List<?> & Appendable> should not be assignable to List<T2 extends Writer & Serializable & Collection<?>>", getRules().matches(new TypeLiteral<List<T2>>() {}.getType(), new TypeLiteral<List<T1>>() {}.getType())); // copy & paste with wildcard Assert.assertFalse("List<T2 extends Writer & Serializable & Collection<?>> should not be assignable to List<? extends T1 extends List<?> & Appendable>", getRules().matches(new TypeLiteral<List<? extends T1>>() {}.getType(), new TypeLiteral<List<T2>>() {}.getType())); Assert.assertFalse("List<T1 extends List<?> & Appendable> should not be assignable to List<? extends T2 extends Writer & Serializable & Collection<?>>", getRules().matches(new TypeLiteral<List<? extends T2>>() {}.getType(), new TypeLiteral<List<T1>>() {}.getType())); } // test that java assignability rules are used to compare parameters of parameterized types @Test public <T1, T2 extends T1, T3 extends Collection<T1>, T4 extends Collection<T2>, T5 extends Collection<Number>, T6 extends Collection<Integer>, T7 extends Collection<?>> void testTypeVariableWithParameterizedTypesAsBounds() { Assert.assertTrue("List<T5 extends Collection<Number>> should be assignable to itself", getRules().matches(new TypeLiteral<List<T5>>() {}.getType(), new TypeLiteral<List<T5>>() {}.getType())); Assert.assertFalse("List<T5 extends Collection<Number>> should not be assignable to List<T6 extends Collection<Integer>>", getRules().matches(new TypeLiteral<List<T6>>() {}.getType(), new TypeLiteral<List<T5>>() {}.getType())); Assert.assertFalse("List<T6 extends Collection<Integer>> should not be assignable to List<T5 extends Collection<Number>>", getRules().matches(new TypeLiteral<List<T5>>() {}.getType(), new TypeLiteral<List<T6>>() {}.getType())); Assert.assertFalse("List<T5 extends Collection<Number>> should not be assignable to List<T7 extends Collection<?>>", getRules().matches(new TypeLiteral<List<T7>>() {}.getType(), new TypeLiteral<List<T5>>() {}.getType())); Assert.assertTrue("List<T3 extends Collection<T1>> should be assignable to itself", getRules().matches(new TypeLiteral<List<T3>>() {}.getType(), new TypeLiteral<List<T3>>() {}.getType())); Assert.assertFalse("List<T3 extends Collection<T1>> should not be assignable to List<T4 extends Collection<T2 extends T1>>", getRules().matches(new TypeLiteral<List<T4>>() {}.getType(), new TypeLiteral<List<T3>>() {}.getType())); Assert.assertFalse("List<T4 extends Collection<T2 extends T1>> should not be assignable to List<T3 extends Collection<T1>>", getRules().matches(new TypeLiteral<List<T3>>() {}.getType(), new TypeLiteral<List<T4>>() {}.getType())); Assert.assertFalse("List<T3 extends Collection<T1>> should not be assignable to List<T7 extends Collection<?>>", getRules().matches(new TypeLiteral<List<T7>>() {}.getType(), new TypeLiteral<List<T3>>() {}.getType())); } }