private boolean annotationsMatch(TypeDescriptor otherDesc) { Annotation[] anns = getAnnotations(); Annotation[] otherAnns = otherDesc.getAnnotations(); if (anns == otherAnns) { return true; } if (anns.length != otherAnns.length) { return false; } if (anns.length > 0) { for (int i = 0; i < anns.length; i++) { if (!annotationEquals(anns[i], otherAnns[i])) { return false; } } } return true; }
@Override public String toString() { StringBuilder builder = new StringBuilder(); for (Annotation ann : getAnnotations()) { builder.append("@").append(ann.annotationType().getName()).append(' '); } builder.append(getResolvableType().toString()); return builder.toString(); }
@Nullable private static TypeDescriptor getRelatedIfResolvable(TypeDescriptor source, ResolvableType type) { if (type.resolve() == null) { return null; } return new TypeDescriptor(type, null, source.getAnnotations()); }
/** * Create a new type descriptor as an array of the specified type. * <p>For example to create a {@code Map<String,String>[]} use: * <pre class="code"> * TypeDescriptor.array(TypeDescriptor.map(Map.class, TypeDescriptor.value(String.class), TypeDescriptor.value(String.class))); * </pre> * @param elementTypeDescriptor the {@link TypeDescriptor} of the array element or {@code null} * @return an array {@link TypeDescriptor} or {@code null} if {@code elementTypeDescriptor} is {@code null} * @since 3.2.1 */ @Nullable public static TypeDescriptor array(@Nullable TypeDescriptor elementTypeDescriptor) { if (elementTypeDescriptor == null) { return null; } return new TypeDescriptor(ResolvableType.forArrayComponent(elementTypeDescriptor.resolvableType), null, elementTypeDescriptor.getAnnotations()); }
public GenericTypeDescriptor(TypeDescriptor typeDescriptor) { super(typeDescriptor.getResolvableType().getGeneric(), null, typeDescriptor.getAnnotations()); } }
/** * Narrows this {@link TypeDescriptor} by setting its type to the class of the * provided value. * <p>If the value is {@code null}, no narrowing is performed and this TypeDescriptor * is returned unchanged. * <p>Designed to be called by binding frameworks when they read property, field, * or method return values. Allows such frameworks to narrow a TypeDescriptor built * from a declared property, field, or method return value type. For example, a field * declared as {@code java.lang.Object} would be narrowed to {@code java.util.HashMap} * if it was set to a {@code java.util.HashMap} value. The narrowed TypeDescriptor * can then be used to convert the HashMap to some other type. Annotation and nested * type context is preserved by the narrowed copy. * @param value the value to use for narrowing this type descriptor * @return this TypeDescriptor narrowed (returns a copy with its type updated to the * class of the provided value) */ public TypeDescriptor narrow(@Nullable Object value) { if (value == null) { return this; } ResolvableType narrowed = ResolvableType.forType(value.getClass(), getResolvableType()); return new TypeDescriptor(narrowed, value.getClass(), getAnnotations()); }
/** * Cast this {@link TypeDescriptor} to a superclass or implemented interface * preserving annotations and nested type context. * @param superType the super type to cast to (can be {@code null}) * @return a new TypeDescriptor for the up-cast type * @throws IllegalArgumentException if this type is not assignable to the super-type * @since 3.2 */ @Nullable public TypeDescriptor upcast(@Nullable Class<?> superType) { if (superType == null) { return null; } Assert.isAssignable(superType, getType()); return new TypeDescriptor(getResolvableType().as(superType), superType, getAnnotations()); }
@Test public void fieldAnnotated() throws Exception { TypeDescriptor typeDescriptor = new TypeDescriptor(getClass().getField("fieldAnnotated")); assertEquals(1, typeDescriptor.getAnnotations().length); assertNotNull(typeDescriptor.getAnnotation(FieldAnnotation.class)); }
/** * If this type is an array, returns the array's component type. * If this type is a {@code Stream}, returns the stream's component type. * If this type is a {@link Collection} and it is parameterized, returns the Collection's element type. * If the Collection is not parameterized, returns {@code null} indicating the element type is not declared. * @return the array component type or Collection element type, or {@code null} if this type is a * Collection but its element type is not parameterized * @throws IllegalStateException if this type is not a {@code java.util.Collection} or array type */ @Nullable public TypeDescriptor getElementTypeDescriptor() { if (getResolvableType().isArray()) { return new TypeDescriptor(getResolvableType().getComponentType(), null, getAnnotations()); } if (Stream.class.isAssignableFrom(getType())) { return getRelatedIfResolvable(this, getResolvableType().as(Stream.class).getGeneric(0)); } return getRelatedIfResolvable(this, getResolvableType().asCollection().getGeneric(0)); }
@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 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 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 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 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 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 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 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()); }