/* * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.core.convert; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.annotation.Annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.junit.Test; import org.springframework.core.MethodParameter; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; /** * Tests for {@link TypeDescriptor}. * * @author Keith Donald * @author Andy Clement * @author Phillip Webb * @author Sam Brannen * @author Nathan Piper */ @SuppressWarnings("rawtypes") public class TypeDescriptorTests { @Test public void parameterPrimitive() throws Exception { TypeDescriptor desc = new TypeDescriptor(new MethodParameter(getClass().getMethod("testParameterPrimitive", int.class), 0)); assertEquals(int.class, desc.getType()); assertEquals(Integer.class, desc.getObjectType()); assertEquals("int", desc.getName()); assertEquals("int", desc.toString()); assertTrue(desc.isPrimitive()); assertEquals(0, desc.getAnnotations().length); assertFalse(desc.isCollection()); assertFalse(desc.isMap()); } @Test public void parameterScalar() throws Exception { TypeDescriptor desc = new TypeDescriptor(new MethodParameter(getClass().getMethod("testParameterScalar", String.class), 0)); assertEquals(String.class, desc.getType()); assertEquals(String.class, desc.getObjectType()); assertEquals("java.lang.String", desc.getName()); assertEquals("java.lang.String", desc.toString()); assertTrue(!desc.isPrimitive()); assertEquals(0, desc.getAnnotations().length); assertFalse(desc.isCollection()); assertFalse(desc.isArray()); assertFalse(desc.isMap()); } @Test public void parameterList() throws Exception { MethodParameter methodParameter = new MethodParameter(getClass().getMethod("testParameterList", List.class), 0); TypeDescriptor desc = new TypeDescriptor(methodParameter); assertEquals(List.class, desc.getType()); assertEquals(List.class, desc.getObjectType()); assertEquals("java.util.List", desc.getName()); assertEquals("java.util.List<java.util.List<java.util.Map<java.lang.Integer, java.lang.Enum<?>>>>", desc.toString()); assertTrue(!desc.isPrimitive()); assertEquals(0, desc.getAnnotations().length); assertTrue(desc.isCollection()); assertFalse(desc.isArray()); assertEquals(List.class, desc.getElementTypeDescriptor().getType()); assertEquals(TypeDescriptor.nested(methodParameter, 1), desc.getElementTypeDescriptor()); assertEquals(TypeDescriptor.nested(methodParameter, 2), desc.getElementTypeDescriptor().getElementTypeDescriptor()); assertEquals(TypeDescriptor.nested(methodParameter, 3), desc.getElementTypeDescriptor().getElementTypeDescriptor().getMapValueTypeDescriptor()); assertEquals(Integer.class, desc.getElementTypeDescriptor().getElementTypeDescriptor().getMapKeyTypeDescriptor().getType()); assertEquals(Enum.class, desc.getElementTypeDescriptor().getElementTypeDescriptor().getMapValueTypeDescriptor().getType()); assertFalse(desc.isMap()); } @Test public void parameterListNoParamTypes() throws Exception { MethodParameter methodParameter = new MethodParameter(getClass().getMethod("testParameterListNoParamTypes", List.class), 0); TypeDescriptor desc = new TypeDescriptor(methodParameter); assertEquals(List.class, desc.getType()); assertEquals(List.class, desc.getObjectType()); assertEquals("java.util.List", desc.getName()); assertEquals("java.util.List<?>", desc.toString()); assertTrue(!desc.isPrimitive()); assertEquals(0, desc.getAnnotations().length); assertTrue(desc.isCollection()); assertFalse(desc.isArray()); assertNull(desc.getElementTypeDescriptor()); assertFalse(desc.isMap()); } @Test public void parameterArray() throws Exception { MethodParameter methodParameter = new MethodParameter(getClass().getMethod("testParameterArray", Integer[].class), 0); TypeDescriptor desc = new TypeDescriptor(methodParameter); assertEquals(Integer[].class, desc.getType()); assertEquals(Integer[].class, desc.getObjectType()); assertEquals("java.lang.Integer[]", desc.getName()); assertEquals("java.lang.Integer[]", desc.toString()); assertTrue(!desc.isPrimitive()); assertEquals(0, desc.getAnnotations().length); assertFalse(desc.isCollection()); assertTrue(desc.isArray()); assertEquals(Integer.class, desc.getElementTypeDescriptor().getType()); assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementTypeDescriptor()); assertFalse(desc.isMap()); } @Test public void parameterMap() throws Exception { MethodParameter methodParameter = new MethodParameter(getClass().getMethod("testParameterMap", Map.class), 0); TypeDescriptor desc = new TypeDescriptor(methodParameter); assertEquals(Map.class, desc.getType()); assertEquals(Map.class, desc.getObjectType()); assertEquals("java.util.Map", desc.getName()); assertEquals("java.util.Map<java.lang.Integer, java.util.List<java.lang.String>>", desc.toString()); assertTrue(!desc.isPrimitive()); assertEquals(0, desc.getAnnotations().length); assertFalse(desc.isCollection()); assertFalse(desc.isArray()); assertTrue(desc.isMap()); assertEquals(TypeDescriptor.nested(methodParameter, 1), desc.getMapValueTypeDescriptor()); assertEquals(TypeDescriptor.nested(methodParameter, 2), desc.getMapValueTypeDescriptor().getElementTypeDescriptor()); assertEquals(Integer.class, desc.getMapKeyTypeDescriptor().getType()); assertEquals(List.class, desc.getMapValueTypeDescriptor().getType()); assertEquals(String.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getType()); } @Test public void parameterAnnotated() throws Exception { TypeDescriptor t1 = new TypeDescriptor(new MethodParameter(getClass().getMethod("testAnnotatedMethod", String.class), 0)); assertEquals(String.class, t1.getType()); assertEquals(1, t1.getAnnotations().length); assertNotNull(t1.getAnnotation(ParameterAnnotation.class)); assertTrue(t1.hasAnnotation(ParameterAnnotation.class)); assertEquals(123, t1.getAnnotation(ParameterAnnotation.class).value()); } @Test public void propertyComplex() throws Exception { Property property = new Property(getClass(), getClass().getMethod("getComplexProperty"), getClass().getMethod("setComplexProperty", Map.class)); TypeDescriptor desc = new TypeDescriptor(property); assertEquals(String.class, desc.getMapKeyTypeDescriptor().getType()); assertEquals(Integer.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getElementTypeDescriptor().getType()); } @Test public void propertyGenericType() throws Exception { GenericType<Integer> genericBean = new IntegerType(); Property property = new Property(getClass(), genericBean.getClass().getMethod("getProperty"), genericBean.getClass().getMethod("setProperty", Integer.class)); TypeDescriptor desc = new TypeDescriptor(property); assertEquals(Integer.class, desc.getType()); } @Test public void propertyTypeCovariance() throws Exception { GenericType<Number> genericBean = new NumberType(); Property property = new Property(getClass(), genericBean.getClass().getMethod("getProperty"), genericBean.getClass().getMethod("setProperty", Number.class)); TypeDescriptor desc = new TypeDescriptor(property); assertEquals(Integer.class, desc.getType()); } @Test public void propertyGenericTypeList() throws Exception { GenericType<Integer> genericBean = new IntegerType(); Property property = new Property(getClass(), genericBean.getClass().getMethod("getListProperty"), genericBean.getClass().getMethod("setListProperty", List.class)); TypeDescriptor desc = new TypeDescriptor(property); assertEquals(List.class, desc.getType()); assertEquals(Integer.class, desc.getElementTypeDescriptor().getType()); } @Test public void propertyGenericClassList() throws Exception { IntegerClass genericBean = new IntegerClass(); Property property = new Property(genericBean.getClass(), genericBean.getClass().getMethod("getListProperty"), genericBean.getClass().getMethod("setListProperty", List.class)); TypeDescriptor desc = new TypeDescriptor(property); assertEquals(List.class, desc.getType()); assertEquals(Integer.class, desc.getElementTypeDescriptor().getType()); assertNotNull(desc.getAnnotation(MethodAnnotation1.class)); assertTrue(desc.hasAnnotation(MethodAnnotation1.class)); } @Test public void property() throws Exception { Property property = new Property( getClass(), getClass().getMethod("getProperty"), getClass().getMethod("setProperty", Map.class)); TypeDescriptor desc = new TypeDescriptor(property); assertEquals(Map.class, desc.getType()); assertEquals(Integer.class, desc.getMapKeyTypeDescriptor().getElementTypeDescriptor().getType()); assertEquals(Long.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getType()); assertNotNull(desc.getAnnotation(MethodAnnotation1.class)); assertNotNull(desc.getAnnotation(MethodAnnotation2.class)); assertNotNull(desc.getAnnotation(MethodAnnotation3.class)); } @Test public void getAnnotationOnMethodThatIsLocallyAnnotated() throws Exception { assertAnnotationFoundOnMethod(MethodAnnotation1.class, "methodWithLocalAnnotation"); } @Test public void getAnnotationOnMethodThatIsMetaAnnotated() throws Exception { assertAnnotationFoundOnMethod(MethodAnnotation1.class, "methodWithComposedAnnotation"); } @Test public void getAnnotationOnMethodThatIsMetaMetaAnnotated() throws Exception { assertAnnotationFoundOnMethod(MethodAnnotation1.class, "methodWithComposedComposedAnnotation"); } private void assertAnnotationFoundOnMethod(Class<? extends Annotation> annotationType, String methodName) throws Exception { TypeDescriptor typeDescriptor = new TypeDescriptor(new MethodParameter(getClass().getMethod(methodName), -1)); assertNotNull("Should have found @" + annotationType.getSimpleName() + " on " + methodName + ".", typeDescriptor.getAnnotation(annotationType)); } @Test public void fieldScalar() throws Exception { TypeDescriptor typeDescriptor = new TypeDescriptor(getClass().getField("fieldScalar")); assertFalse(typeDescriptor.isPrimitive()); assertFalse(typeDescriptor.isArray()); assertFalse(typeDescriptor.isCollection()); assertFalse(typeDescriptor.isMap()); assertEquals(Integer.class, typeDescriptor.getType()); assertEquals(Integer.class, typeDescriptor.getObjectType()); } @Test public void fieldList() throws Exception { TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("listOfString")); assertFalse(typeDescriptor.isArray()); assertEquals(List.class, typeDescriptor.getType()); assertEquals(String.class, typeDescriptor.getElementTypeDescriptor().getType()); assertEquals("java.util.List<java.lang.String>", typeDescriptor.toString()); } @Test public void fieldListOfListOfString() throws Exception { TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("listOfListOfString")); assertFalse(typeDescriptor.isArray()); assertEquals(List.class, typeDescriptor.getType()); assertEquals(List.class, typeDescriptor.getElementTypeDescriptor().getType()); assertEquals(String.class, typeDescriptor.getElementTypeDescriptor().getElementTypeDescriptor().getType()); assertEquals("java.util.List<java.util.List<java.lang.String>>", typeDescriptor.toString()); } @Test public void fieldListOfListUnknown() throws Exception { TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("listOfListOfUnknown")); assertFalse(typeDescriptor.isArray()); assertEquals(List.class, typeDescriptor.getType()); assertEquals(List.class, typeDescriptor.getElementTypeDescriptor().getType()); assertNull(typeDescriptor.getElementTypeDescriptor().getElementTypeDescriptor()); assertEquals("java.util.List<java.util.List<?>>", typeDescriptor.toString()); } @Test public void fieldArray() throws Exception { TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("intArray")); assertTrue(typeDescriptor.isArray()); assertEquals(Integer.TYPE,typeDescriptor.getElementTypeDescriptor().getType()); assertEquals("int[]",typeDescriptor.toString()); } @Test public void fieldComplexTypeDescriptor() throws Exception { TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("arrayOfListOfString")); assertTrue(typeDescriptor.isArray()); assertEquals(List.class,typeDescriptor.getElementTypeDescriptor().getType()); assertEquals(String.class, typeDescriptor.getElementTypeDescriptor().getElementTypeDescriptor().getType()); assertEquals("java.util.List<java.lang.String>[]",typeDescriptor.toString()); } @Test public void fieldComplexTypeDescriptor2() throws Exception { TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("nestedMapField")); assertTrue(typeDescriptor.isMap()); assertEquals(String.class,typeDescriptor.getMapKeyTypeDescriptor().getType()); assertEquals(List.class, typeDescriptor.getMapValueTypeDescriptor().getType()); assertEquals(Integer.class, typeDescriptor.getMapValueTypeDescriptor().getElementTypeDescriptor().getType()); assertEquals("java.util.Map<java.lang.String, java.util.List<java.lang.Integer>>", typeDescriptor.toString()); } @Test public void fieldMap() throws Exception { TypeDescriptor desc = new TypeDescriptor(TypeDescriptorTests.class.getField("fieldMap")); assertTrue(desc.isMap()); assertEquals(Integer.class, desc.getMapKeyTypeDescriptor().getElementTypeDescriptor().getType()); assertEquals(Long.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getType()); } @Test public void fieldAnnotated() throws Exception { TypeDescriptor typeDescriptor = new TypeDescriptor(getClass().getField("fieldAnnotated")); assertEquals(1, typeDescriptor.getAnnotations().length); assertNotNull(typeDescriptor.getAnnotation(FieldAnnotation.class)); } @Test public void valueOfScalar() { TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(Integer.class); assertFalse(typeDescriptor.isPrimitive()); assertFalse(typeDescriptor.isArray()); assertFalse(typeDescriptor.isCollection()); assertFalse(typeDescriptor.isMap()); assertEquals(Integer.class, typeDescriptor.getType()); assertEquals(Integer.class, typeDescriptor.getObjectType()); } @Test public void valueOfPrimitive() { TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(int.class); assertTrue(typeDescriptor.isPrimitive()); assertFalse(typeDescriptor.isArray()); assertFalse(typeDescriptor.isCollection()); assertFalse(typeDescriptor.isMap()); assertEquals(Integer.TYPE, typeDescriptor.getType()); assertEquals(Integer.class, typeDescriptor.getObjectType()); } @Test public void valueOfArray() throws Exception { TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(int[].class); assertTrue(typeDescriptor.isArray()); assertFalse(typeDescriptor.isCollection()); assertFalse(typeDescriptor.isMap()); assertEquals(Integer.TYPE, typeDescriptor.getElementTypeDescriptor().getType()); } @Test public void valueOfCollection() throws Exception { TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(Collection.class); assertTrue(typeDescriptor.isCollection()); assertFalse(typeDescriptor.isArray()); assertFalse(typeDescriptor.isMap()); assertNull(typeDescriptor.getElementTypeDescriptor()); } @Test public void forObject() { TypeDescriptor desc = TypeDescriptor.forObject("3"); assertEquals(String.class, desc.getType()); } @Test public void forObjectNullTypeDescriptor() { TypeDescriptor desc = TypeDescriptor.forObject(null); assertNull(desc); } @Test public void nestedMethodParameterType2Levels() throws Exception { TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test2", List.class), 0), 2); assertEquals(String.class, t1.getType()); } @Test public void nestedMethodParameterTypeMap() throws Exception { TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test3", Map.class), 0), 1); assertEquals(String.class, t1.getType()); } @Test public void nestedMethodParameterTypeMapTwoLevels() throws Exception { TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test4", List.class), 0), 2); assertEquals(String.class, t1.getType()); } @Test(expected = IllegalArgumentException.class) public void nestedMethodParameterNot1NestedLevel() throws Exception { TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test4", List.class), 0, 2), 2); } @Test public void nestedTooManyLevels() throws Exception { TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test4", List.class), 0), 3); assertNull(t1); } @Test public void nestedMethodParameterTypeNotNestable() throws Exception { TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test5", String.class), 0), 2); assertNull(t1); } @Test(expected = IllegalArgumentException.class) public void nestedMethodParameterTypeInvalidNestingLevel() throws Exception { TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test5", String.class), 0, 2), 2); } @Test public void nestedNotParameterized() throws Exception { TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test6", List.class), 0), 1); assertEquals(List.class,t1.getType()); assertEquals("java.util.List<?>", t1.toString()); TypeDescriptor t2 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test6", List.class), 0), 2); assertNull(t2); } @Test public void nestedFieldTypeMapTwoLevels() throws Exception { TypeDescriptor t1 = TypeDescriptor.nested(getClass().getField("test4"), 2); assertEquals(String.class, t1.getType()); } @Test public void nestedPropertyTypeMapTwoLevels() throws Exception { Property property = new Property(getClass(), getClass().getMethod("getTest4"), getClass().getMethod("setTest4", List.class)); TypeDescriptor t1 = TypeDescriptor.nested(property, 2); assertEquals(String.class, t1.getType()); } @Test public void collection() { TypeDescriptor desc = TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Integer.class)); assertEquals(List.class, desc.getType()); assertEquals(List.class, desc.getObjectType()); assertEquals("java.util.List", desc.getName()); assertEquals("java.util.List<java.lang.Integer>", desc.toString()); assertTrue(!desc.isPrimitive()); assertEquals(0, desc.getAnnotations().length); assertTrue(desc.isCollection()); assertFalse(desc.isArray()); assertEquals(Integer.class, desc.getElementTypeDescriptor().getType()); assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementTypeDescriptor()); assertFalse(desc.isMap()); } @Test public void collectionNested() { TypeDescriptor desc = TypeDescriptor.collection(List.class, TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Integer.class))); assertEquals(List.class, desc.getType()); assertEquals(List.class, desc.getObjectType()); assertEquals("java.util.List", desc.getName()); assertEquals("java.util.List<java.util.List<java.lang.Integer>>", desc.toString()); assertTrue(!desc.isPrimitive()); assertEquals(0, desc.getAnnotations().length); assertTrue(desc.isCollection()); assertFalse(desc.isArray()); assertEquals(List.class, desc.getElementTypeDescriptor().getType()); assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementTypeDescriptor().getElementTypeDescriptor()); assertFalse(desc.isMap()); } @Test public void map() { TypeDescriptor desc = TypeDescriptor.map(Map.class, TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(Integer.class)); assertEquals(Map.class, desc.getType()); assertEquals(Map.class, desc.getObjectType()); assertEquals("java.util.Map", desc.getName()); assertEquals("java.util.Map<java.lang.String, java.lang.Integer>", desc.toString()); assertTrue(!desc.isPrimitive()); assertEquals(0, desc.getAnnotations().length); assertFalse(desc.isCollection()); assertFalse(desc.isArray()); assertTrue(desc.isMap()); assertEquals(String.class, desc.getMapKeyTypeDescriptor().getType()); assertEquals(Integer.class, desc.getMapValueTypeDescriptor().getType()); } @Test public void mapNested() { TypeDescriptor desc = TypeDescriptor.map(Map.class, TypeDescriptor.valueOf(String.class), TypeDescriptor.map(Map.class, TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(Integer.class))); assertEquals(Map.class, desc.getType()); assertEquals(Map.class, desc.getObjectType()); assertEquals("java.util.Map", desc.getName()); assertEquals("java.util.Map<java.lang.String, java.util.Map<java.lang.String, java.lang.Integer>>", desc.toString()); assertTrue(!desc.isPrimitive()); assertEquals(0, desc.getAnnotations().length); assertFalse(desc.isCollection()); assertFalse(desc.isArray()); assertTrue(desc.isMap()); assertEquals(String.class, desc.getMapKeyTypeDescriptor().getType()); assertEquals(String.class, desc.getMapValueTypeDescriptor().getMapKeyTypeDescriptor().getType()); assertEquals(Integer.class, desc.getMapValueTypeDescriptor().getMapValueTypeDescriptor().getType()); } @Test public void narrow() { TypeDescriptor desc = TypeDescriptor.valueOf(Number.class); Integer value = new Integer(3); desc = desc.narrow(value); assertEquals(Integer.class, desc.getType()); } @Test public void elementType() { TypeDescriptor desc = TypeDescriptor.valueOf(List.class); Integer value = new Integer(3); desc = desc.elementTypeDescriptor(value); assertEquals(Integer.class, desc.getType()); } @Test public void elementTypePreserveContext() throws Exception { TypeDescriptor desc = new TypeDescriptor(getClass().getField("listPreserveContext")); assertEquals(Integer.class, desc.getElementTypeDescriptor().getElementTypeDescriptor().getType()); List<Integer> value = new ArrayList<>(3); desc = desc.elementTypeDescriptor(value); assertEquals(Integer.class, desc.getElementTypeDescriptor().getType()); assertNotNull(desc.getAnnotation(FieldAnnotation.class)); } @Test public void mapKeyType() { TypeDescriptor desc = TypeDescriptor.valueOf(Map.class); Integer value = new Integer(3); desc = desc.getMapKeyTypeDescriptor(value); assertEquals(Integer.class, desc.getType()); } @Test public void mapKeyTypePreserveContext() throws Exception { TypeDescriptor desc = new TypeDescriptor(getClass().getField("mapPreserveContext")); assertEquals(Integer.class, desc.getMapKeyTypeDescriptor().getElementTypeDescriptor().getType()); List<Integer> value = new ArrayList<>(3); desc = desc.getMapKeyTypeDescriptor(value); assertEquals(Integer.class, desc.getElementTypeDescriptor().getType()); assertNotNull(desc.getAnnotation(FieldAnnotation.class)); } @Test public void mapValueType() { TypeDescriptor desc = TypeDescriptor.valueOf(Map.class); Integer value = new Integer(3); desc = desc.getMapValueTypeDescriptor(value); assertEquals(Integer.class, desc.getType()); } @Test public void mapValueTypePreserveContext() throws Exception { TypeDescriptor desc = new TypeDescriptor(getClass().getField("mapPreserveContext")); assertEquals(Integer.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getType()); List<Integer> value = new ArrayList<>(3); desc = desc.getMapValueTypeDescriptor(value); assertEquals(Integer.class, desc.getElementTypeDescriptor().getType()); assertNotNull(desc.getAnnotation(FieldAnnotation.class)); } @Test public void equality() throws Exception { TypeDescriptor t1 = TypeDescriptor.valueOf(String.class); TypeDescriptor t2 = TypeDescriptor.valueOf(String.class); TypeDescriptor t3 = TypeDescriptor.valueOf(Date.class); TypeDescriptor t4 = TypeDescriptor.valueOf(Date.class); TypeDescriptor t5 = TypeDescriptor.valueOf(List.class); TypeDescriptor t6 = TypeDescriptor.valueOf(List.class); TypeDescriptor t7 = TypeDescriptor.valueOf(Map.class); TypeDescriptor t8 = TypeDescriptor.valueOf(Map.class); assertEquals(t1, t2); assertEquals(t3, t4); assertEquals(t5, t6); assertEquals(t7, t8); TypeDescriptor t9 = new TypeDescriptor(getClass().getField("listField")); TypeDescriptor t10 = new TypeDescriptor(getClass().getField("listField")); assertEquals(t9, t10); TypeDescriptor t11 = new TypeDescriptor(getClass().getField("mapField")); TypeDescriptor t12 = new TypeDescriptor(getClass().getField("mapField")); assertEquals(t11, t12); MethodParameter testAnnotatedMethod = new MethodParameter(getClass().getMethod("testAnnotatedMethod", String.class), 0); TypeDescriptor t13 = new TypeDescriptor(testAnnotatedMethod); TypeDescriptor t14 = new TypeDescriptor(testAnnotatedMethod); assertEquals(t13, t14); TypeDescriptor t15 = new TypeDescriptor(testAnnotatedMethod); TypeDescriptor t16 = new TypeDescriptor(new MethodParameter(getClass().getMethod("testAnnotatedMethodDifferentAnnotationValue", String.class), 0)); assertNotEquals(t15, t16); TypeDescriptor t17 = new TypeDescriptor(testAnnotatedMethod); TypeDescriptor t18 = new TypeDescriptor(new MethodParameter(getClass().getMethod("test5", String.class), 0)); assertNotEquals(t17, t18); } @Test public void isAssignableTypes() { assertTrue(TypeDescriptor.valueOf(Integer.class).isAssignableTo(TypeDescriptor.valueOf(Number.class))); assertFalse(TypeDescriptor.valueOf(Number.class).isAssignableTo(TypeDescriptor.valueOf(Integer.class))); assertFalse(TypeDescriptor.valueOf(String.class).isAssignableTo(TypeDescriptor.valueOf(String[].class))); } @Test public void isAssignableElementTypes() throws Exception { assertTrue(new TypeDescriptor(getClass().getField("listField")).isAssignableTo(new TypeDescriptor(getClass().getField("listField")))); assertTrue(new TypeDescriptor(getClass().getField("notGenericList")).isAssignableTo(new TypeDescriptor(getClass().getField("listField")))); assertTrue(new TypeDescriptor(getClass().getField("listField")).isAssignableTo(new TypeDescriptor(getClass().getField("notGenericList")))); assertFalse(new TypeDescriptor(getClass().getField("isAssignableElementTypes")).isAssignableTo(new TypeDescriptor(getClass().getField("listField")))); assertTrue(TypeDescriptor.valueOf(List.class).isAssignableTo(new TypeDescriptor(getClass().getField("listField")))); } @Test public void isAssignableMapKeyValueTypes() throws Exception { assertTrue(new TypeDescriptor(getClass().getField("mapField")).isAssignableTo(new TypeDescriptor(getClass().getField("mapField")))); assertTrue(new TypeDescriptor(getClass().getField("notGenericMap")).isAssignableTo(new TypeDescriptor(getClass().getField("mapField")))); assertTrue(new TypeDescriptor(getClass().getField("mapField")).isAssignableTo(new TypeDescriptor(getClass().getField("notGenericMap")))); assertFalse(new TypeDescriptor(getClass().getField("isAssignableMapKeyValueTypes")).isAssignableTo(new TypeDescriptor(getClass().getField("mapField")))); assertTrue(TypeDescriptor.valueOf(Map.class).isAssignableTo(new TypeDescriptor(getClass().getField("mapField")))); } @Test public void multiValueMap() throws Exception { TypeDescriptor td = new TypeDescriptor(getClass().getField("multiValueMap")); assertTrue(td.isMap()); assertEquals(String.class, td.getMapKeyTypeDescriptor().getType()); assertEquals(List.class, td.getMapValueTypeDescriptor().getType()); assertEquals(Integer.class, td.getMapValueTypeDescriptor().getElementTypeDescriptor().getType()); } @Test public void passDownGeneric() throws Exception { TypeDescriptor td = new TypeDescriptor(getClass().getField("passDownGeneric")); assertEquals(List.class, td.getElementTypeDescriptor().getType()); assertEquals(Set.class, td.getElementTypeDescriptor().getElementTypeDescriptor().getType()); assertEquals(Integer.class, td.getElementTypeDescriptor().getElementTypeDescriptor().getElementTypeDescriptor().getType()); } @Test public void testUpCast() throws Exception { Property property = new Property(getClass(), getClass().getMethod("getProperty"), getClass().getMethod("setProperty", Map.class)); TypeDescriptor typeDescriptor = new TypeDescriptor(property); TypeDescriptor upCast = typeDescriptor.upcast(Object.class); assertTrue(upCast.getAnnotation(MethodAnnotation1.class) != null); } @Test public void testUpCastNotSuper() throws Exception { Property property = new Property(getClass(), getClass().getMethod("getProperty"), getClass().getMethod("setProperty", Map.class)); TypeDescriptor typeDescriptor = new TypeDescriptor(property); try { typeDescriptor.upcast(Collection.class); fail("Did not throw"); } catch (IllegalArgumentException ex) { assertEquals("interface java.util.Map is not assignable to interface java.util.Collection", ex.getMessage()); } } @Test public void elementTypeForCollectionSubclass() throws Exception { @SuppressWarnings("serial") class CustomSet extends HashSet<String> { } assertEquals(TypeDescriptor.valueOf(CustomSet.class).getElementTypeDescriptor(), TypeDescriptor.valueOf(String.class)); assertEquals(TypeDescriptor.forObject(new CustomSet()).getElementTypeDescriptor(), TypeDescriptor.valueOf(String.class)); } @Test public void elementTypeForMapSubclass() throws Exception { @SuppressWarnings("serial") class CustomMap extends HashMap<String, Integer> { } assertEquals(TypeDescriptor.valueOf(CustomMap.class).getMapKeyTypeDescriptor(), TypeDescriptor.valueOf(String.class)); assertEquals(TypeDescriptor.valueOf(CustomMap.class).getMapValueTypeDescriptor(), TypeDescriptor.valueOf(Integer.class)); assertEquals(TypeDescriptor.forObject(new CustomMap()).getMapKeyTypeDescriptor(), TypeDescriptor.valueOf(String.class)); assertEquals(TypeDescriptor.forObject(new CustomMap()).getMapValueTypeDescriptor(), TypeDescriptor.valueOf(Integer.class)); } @Test public void createMapArray() throws Exception { TypeDescriptor mapType = TypeDescriptor.map( LinkedHashMap.class, TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(Integer.class)); TypeDescriptor arrayType = TypeDescriptor.array(mapType); assertEquals(arrayType.getType(), LinkedHashMap[].class); assertEquals(arrayType.getElementTypeDescriptor(), mapType); } @Test public void createStringArray() throws Exception { TypeDescriptor arrayType = TypeDescriptor.array(TypeDescriptor.valueOf(String.class)); assertEquals(arrayType, TypeDescriptor.valueOf(String[].class)); } @Test public void createNullArray() throws Exception { assertNull(TypeDescriptor.array(null)); } @Test public void serializable() throws Exception { TypeDescriptor typeDescriptor = TypeDescriptor.forObject(""); ByteArrayOutputStream out = new ByteArrayOutputStream(); ObjectOutputStream outputStream = new ObjectOutputStream(out); outputStream.writeObject(typeDescriptor); ObjectInputStream inputStream = new ObjectInputStream(new ByteArrayInputStream( out.toByteArray())); TypeDescriptor readObject = (TypeDescriptor) inputStream.readObject(); assertThat(readObject, equalTo(typeDescriptor)); } @Test public void createCollectionWithNullElement() throws Exception { TypeDescriptor typeDescriptor = TypeDescriptor.collection(List.class, null); assertThat(typeDescriptor.getElementTypeDescriptor(), nullValue()); } @Test public void createMapWithNullElements() throws Exception { TypeDescriptor typeDescriptor = TypeDescriptor.map(LinkedHashMap.class, null, null); assertThat(typeDescriptor.getMapKeyTypeDescriptor(), nullValue()); assertThat(typeDescriptor.getMapValueTypeDescriptor(), nullValue()); } @Test public void getSource() throws Exception { Field field = getClass().getField("fieldScalar"); MethodParameter methodParameter = new MethodParameter(getClass().getMethod("testParameterPrimitive", int.class), 0); assertThat(new TypeDescriptor(field).getSource(), equalTo((Object) field)); assertThat(new TypeDescriptor(methodParameter).getSource(), equalTo((Object) methodParameter)); assertThat(TypeDescriptor.valueOf(Integer.class).getSource(), equalTo((Object) Integer.class)); } // Methods designed for test introspection public void testParameterPrimitive(int primitive) { } public void testParameterScalar(String value) { } public void testParameterList(List<List<Map<Integer, Enum<?>>>> list) { } public void testParameterListNoParamTypes(List list) { } public void testParameterArray(Integer[] array) { } public void testParameterMap(Map<Integer, List<String>> map) { } public void test1(List<String> param1) { } public void test2(List<List<String>> param1) { } public void test3(Map<Integer, String> param1) { } public void test4(List<Map<Integer, String>> param1) { } public void test5(String param1) { } public void test6(List<List> param1) { } public List<Map<Integer, String>> getTest4() { return null; } public void setTest4(List<Map<Integer, String>> test4) { } public Map<String, List<List<Integer>>> getComplexProperty() { return null; } @MethodAnnotation1 public Map<List<Integer>, List<Long>> getProperty() { return property; } @MethodAnnotation2 public void setProperty(Map<List<Integer>, List<Long>> property) { this.property = property; } @MethodAnnotation1 public void methodWithLocalAnnotation() { } @ComposedMethodAnnotation1 public void methodWithComposedAnnotation() { } @ComposedComposedMethodAnnotation1 public void methodWithComposedComposedAnnotation() { } public void setComplexProperty(Map<String, List<List<Integer>>> complexProperty) { } public void testAnnotatedMethod(@ParameterAnnotation(123) String parameter) { } public void testAnnotatedMethodDifferentAnnotationValue(@ParameterAnnotation(567) String parameter) { } // Fields designed for test introspection public Integer fieldScalar; public List<String> listOfString; public List<List<String>> listOfListOfString = new ArrayList<>(); public List<List> listOfListOfUnknown = new ArrayList<>(); public int[] intArray; public List<String>[] arrayOfListOfString; public List<Integer> listField = new ArrayList<>(); public Map<String, Integer> mapField = new HashMap<>(); public Map<String, List<Integer>> nestedMapField = new HashMap<>(); public Map<List<Integer>, List<Long>> fieldMap; public List<Map<Integer, String>> test4; @FieldAnnotation public List<String> fieldAnnotated; @FieldAnnotation public List<List<Integer>> listPreserveContext; @FieldAnnotation public Map<List<Integer>, List<Integer>> mapPreserveContext; @MethodAnnotation3 private Map<List<Integer>, List<Long>> property; public List notGenericList; public List<Number> isAssignableElementTypes; public Map notGenericMap; public Map<CharSequence, Number> isAssignableMapKeyValueTypes; public MultiValueMap<String, Integer> multiValueMap = new LinkedMultiValueMap<>(); public PassDownGeneric<Integer> passDownGeneric = new PassDownGeneric<>(); // Classes designed for test introspection @SuppressWarnings("serial") public static class PassDownGeneric<T> extends ArrayList<List<Set<T>>> { } public static class GenericClass<T> { public T getProperty() { return null; } public void setProperty(T t) { } @MethodAnnotation1 public List<T> getListProperty() { return null; } public void setListProperty(List<T> t) { } } public static class IntegerClass extends GenericClass<Integer> { } public interface GenericType<T> { T getProperty(); void setProperty(T t); List<T> getListProperty(); void setListProperty(List<T> t); } public class IntegerType implements GenericType<Integer> { @Override public Integer getProperty() { return null; } @Override public void setProperty(Integer t) { } @Override public List<Integer> getListProperty() { return null; } @Override public void setListProperty(List<Integer> t) { } } public class NumberType implements GenericType<Number> { @Override public Integer getProperty() { return null; } @Override public void setProperty(Number t) { } @Override public List<Number> getListProperty() { return null; } @Override public void setListProperty(List<Number> t) { } } // Annotations used on tested elements @Target({ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) public @interface ParameterAnnotation { int value(); } @Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface FieldAnnotation { } @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface MethodAnnotation1 { } @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface MethodAnnotation2 { } @Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface MethodAnnotation3 { } @MethodAnnotation1 @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface ComposedMethodAnnotation1 { } @ComposedMethodAnnotation1 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface ComposedComposedMethodAnnotation1 { } }