From de0cb533942fc25d2cbe00b71225b7d8f07e0a6d Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 24 Oct 2023 23:32:17 +0200 Subject: [PATCH] Polishing (cherry picked from commit 925fa0272b76c765d3f9dee2bd5d54c66bd849c9) --- .../AbstractNestablePropertyAccessor.java | 6 +- .../beans/DirectFieldAccessor.java | 3 +- ...AbstractApplicationEventListenerTests.java | 24 ++- ...enericApplicationListenerAdapterTests.java | 5 +- .../springframework/core/ResolvableType.java | 179 +++++++++--------- .../core/ResolvableTypeTests.java | 61 +++--- 6 files changed, 143 insertions(+), 135 deletions(-) diff --git a/spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java b/spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java index b56ec6b9533b..7638a8af8b68 100644 --- a/spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java +++ b/spring-beans/src/main/java/org/springframework/beans/AbstractNestablePropertyAccessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2023 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. @@ -1004,18 +1004,20 @@ public String toString() { */ protected abstract static class PropertyHandler { + @Nullable private final Class propertyType; private final boolean readable; private final boolean writable; - public PropertyHandler(Class propertyType, boolean readable, boolean writable) { + public PropertyHandler(@Nullable Class propertyType, boolean readable, boolean writable) { this.propertyType = propertyType; this.readable = readable; this.writable = writable; } + @Nullable public Class getPropertyType() { return this.propertyType; } diff --git a/spring-beans/src/main/java/org/springframework/beans/DirectFieldAccessor.java b/spring-beans/src/main/java/org/springframework/beans/DirectFieldAccessor.java index a98c6eb41b03..0a9b39e2e477 100644 --- a/spring-beans/src/main/java/org/springframework/beans/DirectFieldAccessor.java +++ b/spring-beans/src/main/java/org/springframework/beans/DirectFieldAccessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2023 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. @@ -129,7 +129,6 @@ public Object getValue() throws Exception { ReflectionUtils.makeAccessible(this.field); return this.field.get(getWrappedInstance()); } - catch (IllegalAccessException ex) { throw new InvalidPropertyException(getWrappedClass(), this.field.getName(), "Field is not accessible", ex); diff --git a/spring-context/src/test/java/org/springframework/context/event/AbstractApplicationEventListenerTests.java b/spring-context/src/test/java/org/springframework/context/event/AbstractApplicationEventListenerTests.java index bf4360ef589b..22d33a109cb9 100644 --- a/spring-context/src/test/java/org/springframework/context/event/AbstractApplicationEventListenerTests.java +++ b/spring-context/src/test/java/org/springframework/context/event/AbstractApplicationEventListenerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2023 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. @@ -36,6 +36,10 @@ protected ResolvableType getGenericApplicationEventType(String fieldName) { } } + protected GenericTestEvent createGenericTestEvent(T payload) { + return new GenericTestEvent<>(this, payload); + } + protected static class GenericTestEvent extends ApplicationEvent { @@ -51,6 +55,7 @@ public T getPayload() { } } + protected static class SmartGenericTestEvent extends GenericTestEvent implements ResolvableTypeProvider { private final ResolvableType resolvableType; @@ -67,6 +72,7 @@ public ResolvableType getResolvableType() { } } + protected static class StringEvent extends GenericTestEvent { public StringEvent(Object source, String payload) { @@ -74,6 +80,7 @@ public StringEvent(Object source, String payload) { } } + protected static class LongEvent extends GenericTestEvent { public LongEvent(Object source, Long payload) { @@ -81,31 +88,31 @@ public LongEvent(Object source, Long payload) { } } - protected GenericTestEvent createGenericTestEvent(T payload) { - return new GenericTestEvent<>(this, payload); - } - static class GenericEventListener implements ApplicationListener> { + @Override public void onApplicationEvent(GenericTestEvent event) { } } + static class ObjectEventListener implements ApplicationListener> { + @Override public void onApplicationEvent(GenericTestEvent event) { } } - static class UpperBoundEventListener - implements ApplicationListener> { + + static class UpperBoundEventListener implements ApplicationListener> { @Override public void onApplicationEvent(GenericTestEvent event) { } } + static class StringEventListener implements ApplicationListener> { @Override @@ -113,6 +120,7 @@ public void onApplicationEvent(GenericTestEvent event) { } } + @SuppressWarnings("rawtypes") static class RawApplicationListener implements ApplicationListener { @@ -121,10 +129,10 @@ public void onApplicationEvent(ApplicationEvent event) { } } + static class TestEvents { public GenericTestEvent wildcardEvent; - } } diff --git a/spring-context/src/test/java/org/springframework/context/event/GenericApplicationListenerAdapterTests.java b/spring-context/src/test/java/org/springframework/context/event/GenericApplicationListenerAdapterTests.java index 7c0e299791e8..12682a5dcee3 100644 --- a/spring-context/src/test/java/org/springframework/context/event/GenericApplicationListenerAdapterTests.java +++ b/spring-context/src/test/java/org/springframework/context/event/GenericApplicationListenerAdapterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2023 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. @@ -104,7 +104,8 @@ public void genericListenerStrictTypeNotMatchTypeErasure() { @Test public void genericListenerStrictTypeSubClass() { - supportsEventType(false, ObjectEventListener.class, ResolvableType.forClassWithGenerics(GenericTestEvent.class, Long.class)); + supportsEventType(false, ObjectEventListener.class, + ResolvableType.forClassWithGenerics(GenericTestEvent.class, Long.class)); } @Test diff --git a/spring-core/src/main/java/org/springframework/core/ResolvableType.java b/spring-core/src/main/java/org/springframework/core/ResolvableType.java index fa0f963f46d8..a56670b4b5dc 100644 --- a/spring-core/src/main/java/org/springframework/core/ResolvableType.java +++ b/spring-core/src/main/java/org/springframework/core/ResolvableType.java @@ -138,7 +138,7 @@ public class ResolvableType implements Serializable { /** - * Private constructor used to create a new {@link ResolvableType} for cache key purposes, + * Private constructor used to create a new {@code ResolvableType} for cache key purposes, * with no upfront resolution. */ private ResolvableType( @@ -153,7 +153,7 @@ private ResolvableType( } /** - * Private constructor used to create a new {@link ResolvableType} for cache value purposes, + * Private constructor used to create a new {@code ResolvableType} for cache value purposes, * with upfront resolution and a pre-calculated hash. * @since 4.2 */ @@ -169,7 +169,7 @@ private ResolvableType(Type type, @Nullable TypeProvider typeProvider, } /** - * Private constructor used to create a new {@link ResolvableType} for uncached purposes, + * Private constructor used to create a new {@code ResolvableType} for uncached purposes, * with upfront resolution but lazily calculated hash. */ private ResolvableType(Type type, @Nullable TypeProvider typeProvider, @@ -184,7 +184,7 @@ private ResolvableType(Type type, @Nullable TypeProvider typeProvider, } /** - * Private constructor used to create a new {@link ResolvableType} on a {@link Class} basis. + * Private constructor used to create a new {@code ResolvableType} on a {@link Class} basis. *

Avoids all {@code instanceof} checks in order to create a straight {@link Class} wrapper. * @since 4.2 */ @@ -223,7 +223,7 @@ public Class getRawClass() { /** * Return the underlying source of the resolvable type. Will return a {@link Field}, - * {@link MethodParameter} or {@link Type} depending on how the {@link ResolvableType} + * {@link MethodParameter} or {@link Type} depending on how the {@code ResolvableType} * was constructed. This method is primarily to provide access to additional type * information or meta-data that alternative JVM languages may provide. */ @@ -341,13 +341,14 @@ private boolean isAssignableFrom(ResolvableType other, @Nullable Map } } if (ourResolved == null) { - ourResolved = resolve(Object.class); + ourResolved = toClass(); } Class otherResolved = other.toClass(); // We need an exact type match for generics // List is not assignable from List - if (exactMatch ? !ourResolved.equals(otherResolved) : !ClassUtils.isAssignable(ourResolved, otherResolved)) { + if (exactMatch ? !ourResolved.equals(otherResolved) : + !ClassUtils.isAssignable(ourResolved, otherResolved)) { return false; } @@ -358,13 +359,15 @@ private boolean isAssignableFrom(ResolvableType other, @Nullable Map if (ourGenerics.length != typeGenerics.length) { return false; } - if (matchedBefore == null) { - matchedBefore = new IdentityHashMap<>(1); - } - matchedBefore.put(this.type, other.type); - for (int i = 0; i < ourGenerics.length; i++) { - if (!ourGenerics[i].isAssignableFrom(typeGenerics[i], matchedBefore)) { - return false; + if (ourGenerics.length > 0) { + if (matchedBefore == null) { + matchedBefore = new IdentityHashMap<>(1); + } + matchedBefore.put(this.type, other.type); + for (int i = 0; i < ourGenerics.length; i++) { + if (!ourGenerics[i].isAssignableFrom(typeGenerics[i], matchedBefore)) { + return false; + } } } } @@ -429,12 +432,12 @@ public ResolvableType asMap() { } /** - * Return this type as a {@link ResolvableType} of the specified class. Searches + * Return this type as a {@code ResolvableType} of the specified class. Searches * {@link #getSuperType() supertype} and {@link #getInterfaces() interface} * hierarchies to find a match, returning {@link #NONE} if this type does not * implement or extend the specified class. * @param type the required type (typically narrowed) - * @return a {@link ResolvableType} representing this object as the specified + * @return a {@code ResolvableType} representing this object as the specified * type, or {@link #NONE} if not resolvable as that type * @see #asCollection() * @see #asMap() @@ -459,9 +462,9 @@ public ResolvableType as(Class type) { } /** - * Return a {@link ResolvableType} representing the direct supertype of this type. + * Return a {@code ResolvableType} representing the direct supertype of this type. *

If no supertype is available this method returns {@link #NONE}. - *

Note: The resulting {@link ResolvableType} instance may not be {@link Serializable}. + *

Note: The resulting {@code ResolvableType} instance may not be {@link Serializable}. * @see #getInterfaces() */ public ResolvableType getSuperType() { @@ -488,10 +491,10 @@ public ResolvableType getSuperType() { } /** - * Return a {@link ResolvableType} array representing the direct interfaces + * Return a {@code ResolvableType} array representing the direct interfaces * implemented by this type. If this type does not implement any interfaces an * empty array is returned. - *

Note: The resulting {@link ResolvableType} instances may not be {@link Serializable}. + *

Note: The resulting {@code ResolvableType} instances may not be {@link Serializable}. * @see #getSuperType() */ public ResolvableType[] getInterfaces() { @@ -621,17 +624,17 @@ private boolean isWildcardWithoutBounds() { } /** - * Return a {@link ResolvableType} for the specified nesting level. + * Return a {@code ResolvableType} for the specified nesting level. *

See {@link #getNested(int, Map)} for details. * @param nestingLevel the nesting level - * @return the {@link ResolvableType} type, or {@code #NONE} + * @return the {@code ResolvableType} type, or {@code #NONE} */ public ResolvableType getNested(int nestingLevel) { return getNested(nestingLevel, null); } /** - * Return a {@link ResolvableType} for the specified nesting level. + * Return a {@code ResolvableType} for the specified nesting level. *

The nesting level refers to the specific generic parameter that should be returned. * A nesting level of 1 indicates this type; 2 indicates the first nested generic; * 3 the second; and so on. For example, given {@code List>} level 1 refers @@ -648,7 +651,7 @@ public ResolvableType getNested(int nestingLevel) { * current type, 2 for the first nested generic, 3 for the second and so on * @param typeIndexesPerLevel a map containing the generic index for a given * nesting level (may be {@code null}) - * @return a {@link ResolvableType} for the nested level, or {@link #NONE} + * @return a {@code ResolvableType} for the nested level, or {@link #NONE} */ public ResolvableType getNested(int nestingLevel, @Nullable Map typeIndexesPerLevel) { ResolvableType result = this; @@ -670,7 +673,7 @@ public ResolvableType getNested(int nestingLevel, @Nullable Map>}, {@code getGeneric(0)} will access the * {@code Integer}. Nested generics can be accessed by specifying multiple indexes; @@ -680,7 +683,7 @@ public ResolvableType getNested(int nestingLevel, @Nullable MapIf no generic is available at the specified indexes {@link #NONE} is returned. * @param indexes the indexes that refer to the generic parameter * (may be omitted to return the first generic) - * @return a {@link ResolvableType} for the specified generic, or {@link #NONE} + * @return a {@code ResolvableType} for the specified generic, or {@link #NONE} * @see #hasGenerics() * @see #getGenerics() * @see #resolveGeneric(int...) @@ -703,12 +706,12 @@ public ResolvableType getGeneric(@Nullable int... indexes) { } /** - * Return an array of {@link ResolvableType ResolvableTypes} representing the generic parameters of + * Return an array of {@code ResolvableType ResolvableTypes} representing the generic parameters of * this type. If no generics are available an empty array is returned. If you need to * access a specific generic consider using the {@link #getGeneric(int...)} method as * it allows access to nested generics and protects against * {@code IndexOutOfBoundsExceptions}. - * @return an array of {@link ResolvableType ResolvableTypes} representing the generic parameters + * @return an array of {@code ResolvableType ResolvableTypes} representing the generic parameters * (never {@code null}) * @see #hasGenerics() * @see #getGeneric(int...) @@ -780,7 +783,7 @@ public Class[] resolveGenerics(Class fallback) { /** * Convenience method that will {@link #getGeneric(int...) get} and - * {@link #resolve() resolve} a specific generic parameters. + * {@link #resolve() resolve} a specific generic parameter. * @param indexes the indexes that refer to the generic parameter * (may be omitted to return the first generic) * @return a resolved {@link Class} or {@code null} @@ -842,7 +845,7 @@ private Class resolveClass() { /** * Resolve this type by a single level, returning the resolved value or {@link #NONE}. - *

Note: The returned {@link ResolvableType} should only be used as an intermediary + *

Note: The returned {@code ResolvableType} should only be used as an intermediary * as it cannot be serialized. */ ResolvableType resolveType() { @@ -964,7 +967,7 @@ private int calculateHashCode() { } /** - * Adapts this {@link ResolvableType} to a {@link VariableResolver}. + * Adapts this {@code ResolvableType} to a {@link VariableResolver}. */ @Nullable VariableResolver asVariableResolver() { @@ -1011,12 +1014,12 @@ public String toString() { // Factory methods /** - * Return a {@link ResolvableType} for the specified {@link Class}, + * Return a {@code ResolvableType} for the specified {@link Class}, * using the full generic type information for assignability checks. *

For example: {@code ResolvableType.forClass(MyArrayList.class)}. * @param clazz the class to introspect ({@code null} is semantically * equivalent to {@code Object.class} for typical use cases here) - * @return a {@link ResolvableType} for the specified class + * @return a {@code ResolvableType} for the specified class * @see #forClass(Class, Class) * @see #forClassWithGenerics(Class, Class...) */ @@ -1025,13 +1028,13 @@ public static ResolvableType forClass(@Nullable Class clazz) { } /** - * Return a {@link ResolvableType} for the specified {@link Class}, + * Return a {@code ResolvableType} for the specified {@link Class}, * doing assignability checks against the raw class only (analogous to * {@link Class#isAssignableFrom}, which this serves as a wrapper for). *

For example: {@code ResolvableType.forRawClass(List.class)}. * @param clazz the class to introspect ({@code null} is semantically * equivalent to {@code Object.class} for typical use cases here) - * @return a {@link ResolvableType} for the specified class + * @return a {@code ResolvableType} for the specified class * @since 4.2 * @see #forClass(Class) * @see #getRawClass() @@ -1055,12 +1058,12 @@ public boolean isAssignableFrom(ResolvableType other) { } /** - * Return a {@link ResolvableType} for the specified base type + * Return a {@code ResolvableType} for the specified base type * (interface or base class) with a given implementation class. *

For example: {@code ResolvableType.forClass(List.class, MyArrayList.class)}. * @param baseType the base type (must not be {@code null}) * @param implementationClass the implementation class - * @return a {@link ResolvableType} for the specified base type backed by the + * @return a {@code ResolvableType} for the specified base type backed by the * given implementation class * @see #forClass(Class) * @see #forClassWithGenerics(Class, Class...) @@ -1072,10 +1075,10 @@ public static ResolvableType forClass(Class baseType, Class implementation } /** - * Return a {@link ResolvableType} for the specified {@link Class} with pre-declared generics. + * Return a {@code ResolvableType} for the specified {@link Class} with pre-declared generics. * @param clazz the class (or interface) to introspect * @param generics the generics of the class - * @return a {@link ResolvableType} for the specific class and generics + * @return a {@code ResolvableType} for the specific class and generics * @see #forClassWithGenerics(Class, ResolvableType...) */ public static ResolvableType forClassWithGenerics(Class clazz, Class... generics) { @@ -1089,10 +1092,10 @@ public static ResolvableType forClassWithGenerics(Class clazz, Class... ge } /** - * Return a {@link ResolvableType} for the specified {@link Class} with pre-declared generics. + * Return a {@code ResolvableType} for the specified {@link Class} with pre-declared generics. * @param clazz the class (or interface) to introspect * @param generics the generics of the class - * @return a {@link ResolvableType} for the specific class and generics + * @return a {@code ResolvableType} for the specific class and generics * @see #forClassWithGenerics(Class, Class...) */ public static ResolvableType forClassWithGenerics(Class clazz, ResolvableType... generics) { @@ -1113,12 +1116,12 @@ public static ResolvableType forClassWithGenerics(Class clazz, ResolvableType } /** - * Return a {@link ResolvableType} for the specified instance. The instance does not + * Return a {@code ResolvableType} for the specified instance. The instance does not * convey generic information but if it implements {@link ResolvableTypeProvider} a - * more precise {@link ResolvableType} can be used than the simple one based on + * more precise {@code ResolvableType} can be used than the simple one based on * the {@link #forClass(Class) Class instance}. * @param instance the instance (possibly {@code null}) - * @return a {@link ResolvableType} for the specified instance, + * @return a {@code ResolvableType} for the specified instance, * or {@code NONE} for {@code null} * @since 4.2 * @see ResolvableTypeProvider @@ -1134,9 +1137,9 @@ public static ResolvableType forInstance(@Nullable Object instance) { } /** - * Return a {@link ResolvableType} for the specified {@link Field}. + * Return a {@code ResolvableType} for the specified {@link Field}. * @param field the source field - * @return a {@link ResolvableType} for the specified field + * @return a {@code ResolvableType} for the specified field * @see #forField(Field, Class) */ public static ResolvableType forField(Field field) { @@ -1145,13 +1148,13 @@ public static ResolvableType forField(Field field) { } /** - * Return a {@link ResolvableType} for the specified {@link Field} with a given + * Return a {@code ResolvableType} for the specified {@link Field} with a given * implementation. *

Use this variant when the class that declares the field includes generic * parameter variables that are satisfied by the implementation class. * @param field the source field * @param implementationClass the implementation class - * @return a {@link ResolvableType} for the specified field + * @return a {@code ResolvableType} for the specified field * @see #forField(Field) */ public static ResolvableType forField(Field field, Class implementationClass) { @@ -1161,13 +1164,13 @@ public static ResolvableType forField(Field field, Class implementationClass) } /** - * Return a {@link ResolvableType} for the specified {@link Field} with a given + * Return a {@code ResolvableType} for the specified {@link Field} with a given * implementation. *

Use this variant when the class that declares the field includes generic * parameter variables that are satisfied by the implementation type. * @param field the source field * @param implementationType the implementation type - * @return a {@link ResolvableType} for the specified field + * @return a {@code ResolvableType} for the specified field * @see #forField(Field) */ public static ResolvableType forField(Field field, @Nullable ResolvableType implementationType) { @@ -1178,7 +1181,7 @@ public static ResolvableType forField(Field field, @Nullable ResolvableType impl } /** - * Return a {@link ResolvableType} for the specified {@link Field} with the + * Return a {@code ResolvableType} for the specified {@link Field} with the * given nesting level. * @param field the source field * @param nestingLevel the nesting level (1 for the outer level; 2 for a nested @@ -1191,7 +1194,7 @@ public static ResolvableType forField(Field field, int nestingLevel) { } /** - * Return a {@link ResolvableType} for the specified {@link Field} with a given + * Return a {@code ResolvableType} for the specified {@link Field} with a given * implementation and the given nesting level. *

Use this variant when the class that declares the field includes generic * parameter variables that are satisfied by the implementation class. @@ -1199,7 +1202,7 @@ public static ResolvableType forField(Field field, int nestingLevel) { * @param nestingLevel the nesting level (1 for the outer level; 2 for a nested * generic type; etc) * @param implementationClass the implementation class - * @return a {@link ResolvableType} for the specified field + * @return a {@code ResolvableType} for the specified field * @see #forField(Field) */ public static ResolvableType forField(Field field, int nestingLevel, @Nullable Class implementationClass) { @@ -1209,10 +1212,10 @@ public static ResolvableType forField(Field field, int nestingLevel, @Nullable C } /** - * Return a {@link ResolvableType} for the specified {@link Constructor} parameter. + * Return a {@code ResolvableType} for the specified {@link Constructor} parameter. * @param constructor the source constructor (must not be {@code null}) * @param parameterIndex the parameter index - * @return a {@link ResolvableType} for the specified constructor parameter + * @return a {@code ResolvableType} for the specified constructor parameter * @see #forConstructorParameter(Constructor, int, Class) */ public static ResolvableType forConstructorParameter(Constructor constructor, int parameterIndex) { @@ -1221,14 +1224,14 @@ public static ResolvableType forConstructorParameter(Constructor constructor, } /** - * Return a {@link ResolvableType} for the specified {@link Constructor} parameter + * Return a {@code ResolvableType} for the specified {@link Constructor} parameter * with a given implementation. Use this variant when the class that declares the * constructor includes generic parameter variables that are satisfied by the * implementation class. * @param constructor the source constructor (must not be {@code null}) * @param parameterIndex the parameter index * @param implementationClass the implementation class - * @return a {@link ResolvableType} for the specified constructor parameter + * @return a {@code ResolvableType} for the specified constructor parameter * @see #forConstructorParameter(Constructor, int) */ public static ResolvableType forConstructorParameter(Constructor constructor, int parameterIndex, @@ -1240,9 +1243,9 @@ public static ResolvableType forConstructorParameter(Constructor constructor, } /** - * Return a {@link ResolvableType} for the specified {@link Method} return type. + * Return a {@code ResolvableType} for the specified {@link Method} return type. * @param method the source for the method return type - * @return a {@link ResolvableType} for the specified method return + * @return a {@code ResolvableType} for the specified method return * @see #forMethodReturnType(Method, Class) */ public static ResolvableType forMethodReturnType(Method method) { @@ -1251,12 +1254,12 @@ public static ResolvableType forMethodReturnType(Method method) { } /** - * Return a {@link ResolvableType} for the specified {@link Method} return type. + * Return a {@code ResolvableType} for the specified {@link Method} return type. *

Use this variant when the class that declares the method includes generic * parameter variables that are satisfied by the implementation class. * @param method the source for the method return type * @param implementationClass the implementation class - * @return a {@link ResolvableType} for the specified method return + * @return a {@code ResolvableType} for the specified method return * @see #forMethodReturnType(Method) */ public static ResolvableType forMethodReturnType(Method method, Class implementationClass) { @@ -1266,10 +1269,10 @@ public static ResolvableType forMethodReturnType(Method method, Class impleme } /** - * Return a {@link ResolvableType} for the specified {@link Method} parameter. + * Return a {@code ResolvableType} for the specified {@link Method} parameter. * @param method the source method (must not be {@code null}) * @param parameterIndex the parameter index - * @return a {@link ResolvableType} for the specified method parameter + * @return a {@code ResolvableType} for the specified method parameter * @see #forMethodParameter(Method, int, Class) * @see #forMethodParameter(MethodParameter) */ @@ -1279,13 +1282,13 @@ public static ResolvableType forMethodParameter(Method method, int parameterInde } /** - * Return a {@link ResolvableType} for the specified {@link Method} parameter with a + * Return a {@code ResolvableType} for the specified {@link Method} parameter with a * given implementation. Use this variant when the class that declares the method * includes generic parameter variables that are satisfied by the implementation class. * @param method the source method (must not be {@code null}) * @param parameterIndex the parameter index * @param implementationClass the implementation class - * @return a {@link ResolvableType} for the specified method parameter + * @return a {@code ResolvableType} for the specified method parameter * @see #forMethodParameter(Method, int, Class) * @see #forMethodParameter(MethodParameter) */ @@ -1296,9 +1299,9 @@ public static ResolvableType forMethodParameter(Method method, int parameterInde } /** - * Return a {@link ResolvableType} for the specified {@link MethodParameter}. + * Return a {@code ResolvableType} for the specified {@link MethodParameter}. * @param methodParameter the source method parameter (must not be {@code null}) - * @return a {@link ResolvableType} for the specified method parameter + * @return a {@code ResolvableType} for the specified method parameter * @see #forMethodParameter(Method, int) */ public static ResolvableType forMethodParameter(MethodParameter methodParameter) { @@ -1306,12 +1309,12 @@ public static ResolvableType forMethodParameter(MethodParameter methodParameter) } /** - * Return a {@link ResolvableType} for the specified {@link MethodParameter} with a + * Return a {@code ResolvableType} for the specified {@link MethodParameter} with a * given implementation type. Use this variant when the class that declares the method * includes generic parameter variables that are satisfied by the implementation type. * @param methodParameter the source method parameter (must not be {@code null}) * @param implementationType the implementation type - * @return a {@link ResolvableType} for the specified method parameter + * @return a {@code ResolvableType} for the specified method parameter * @see #forMethodParameter(MethodParameter) */ public static ResolvableType forMethodParameter(MethodParameter methodParameter, @@ -1326,11 +1329,11 @@ public static ResolvableType forMethodParameter(MethodParameter methodParameter, } /** - * Return a {@link ResolvableType} for the specified {@link MethodParameter}, + * Return a {@code ResolvableType} for the specified {@link MethodParameter}, * overriding the target type to resolve with a specific given type. * @param methodParameter the source method parameter (must not be {@code null}) * @param targetType the type to resolve (a part of the method parameter's type) - * @return a {@link ResolvableType} for the specified method parameter + * @return a {@code ResolvableType} for the specified method parameter * @see #forMethodParameter(Method, int) */ public static ResolvableType forMethodParameter(MethodParameter methodParameter, @Nullable Type targetType) { @@ -1339,13 +1342,13 @@ public static ResolvableType forMethodParameter(MethodParameter methodParameter, } /** - * Return a {@link ResolvableType} for the specified {@link MethodParameter} at + * Return a {@code ResolvableType} for the specified {@link MethodParameter} at * a specific nesting level, overriding the target type to resolve with a specific * given type. * @param methodParameter the source method parameter (must not be {@code null}) * @param targetType the type to resolve (a part of the method parameter's type) * @param nestingLevel the nesting level to use - * @return a {@link ResolvableType} for the specified method parameter + * @return a {@code ResolvableType} for the specified method parameter * @since 5.2 * @see #forMethodParameter(Method, int) */ @@ -1358,9 +1361,9 @@ static ResolvableType forMethodParameter( } /** - * Return a {@link ResolvableType} as an array of the specified {@code componentType}. + * Return a {@code ResolvableType} as an array of the specified {@code componentType}. * @param componentType the component type - * @return a {@link ResolvableType} as an array of the specified component type + * @return a {@code ResolvableType} as an array of the specified component type */ public static ResolvableType forArrayComponent(ResolvableType componentType) { Assert.notNull(componentType, "Component type must not be null"); @@ -1369,10 +1372,10 @@ public static ResolvableType forArrayComponent(ResolvableType componentType) { } /** - * Return a {@link ResolvableType} for the specified {@link Type}. - *

Note: The resulting {@link ResolvableType} instance may not be {@link Serializable}. + * Return a {@code ResolvableType} for the specified {@link Type}. + *

Note: The resulting {@code ResolvableType} instance may not be {@link Serializable}. * @param type the source type (potentially {@code null}) - * @return a {@link ResolvableType} for the specified {@link Type} + * @return a {@code ResolvableType} for the specified {@link Type} * @see #forType(Type, ResolvableType) */ public static ResolvableType forType(@Nullable Type type) { @@ -1380,12 +1383,12 @@ public static ResolvableType forType(@Nullable Type type) { } /** - * Return a {@link ResolvableType} for the specified {@link Type} backed by the given + * Return a {@code ResolvableType} for the specified {@link Type} backed by the given * owner type. - *

Note: The resulting {@link ResolvableType} instance may not be {@link Serializable}. + *

Note: The resulting {@code ResolvableType} instance may not be {@link Serializable}. * @param type the source type or {@code null} * @param owner the owner type used to resolve variables - * @return a {@link ResolvableType} for the specified {@link Type} and owner + * @return a {@code ResolvableType} for the specified {@link Type} and owner * @see #forType(Type) */ public static ResolvableType forType(@Nullable Type type, @Nullable ResolvableType owner) { @@ -1398,10 +1401,10 @@ public static ResolvableType forType(@Nullable Type type, @Nullable ResolvableTy /** - * Return a {@link ResolvableType} for the specified {@link ParameterizedTypeReference}. - *

Note: The resulting {@link ResolvableType} instance may not be {@link Serializable}. + * Return a {@code ResolvableType} for the specified {@link ParameterizedTypeReference}. + *

Note: The resulting {@code ResolvableType} instance may not be {@link Serializable}. * @param typeReference the reference to obtain the source type from - * @return a {@link ResolvableType} for the specified {@link ParameterizedTypeReference} + * @return a {@code ResolvableType} for the specified {@link ParameterizedTypeReference} * @since 4.3.12 * @see #forType(Type) */ @@ -1410,23 +1413,23 @@ public static ResolvableType forType(ParameterizedTypeReference typeReference } /** - * Return a {@link ResolvableType} for the specified {@link Type} backed by a given + * Return a {@code ResolvableType} for the specified {@link Type} backed by a given * {@link VariableResolver}. * @param type the source type or {@code null} * @param variableResolver the variable resolver or {@code null} - * @return a {@link ResolvableType} for the specified {@link Type} and {@link VariableResolver} + * @return a {@code ResolvableType} for the specified {@link Type} and {@link VariableResolver} */ static ResolvableType forType(@Nullable Type type, @Nullable VariableResolver variableResolver) { return forType(type, null, variableResolver); } /** - * Return a {@link ResolvableType} for the specified {@link Type} backed by a given + * Return a {@code ResolvableType} for the specified {@link Type} backed by a given * {@link VariableResolver}. * @param type the source type or {@code null} * @param typeProvider the type provider or {@code null} * @param variableResolver the variable resolver or {@code null} - * @return a {@link ResolvableType} for the specified {@link Type} and {@link VariableResolver} + * @return a {@code ResolvableType} for the specified {@link Type} and {@link VariableResolver} */ static ResolvableType forType( @Nullable Type type, @Nullable TypeProvider typeProvider, @Nullable VariableResolver variableResolver) { diff --git a/spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java b/spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java index 48641a7c70c8..a3192bd91cc3 100644 --- a/spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java +++ b/spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2023 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. @@ -200,8 +200,8 @@ void forPrivateField() throws Exception { @Test void forFieldMustNotBeNull() throws Exception { assertThatIllegalArgumentException() - .isThrownBy(() -> ResolvableType.forField(null)) - .withMessage("Field must not be null"); + .isThrownBy(() -> ResolvableType.forField(null)) + .withMessage("Field must not be null"); } @Test @@ -214,8 +214,8 @@ void forConstructorParameter() throws Exception { @Test void forConstructorParameterMustNotBeNull() throws Exception { assertThatIllegalArgumentException() - .isThrownBy(() -> ResolvableType.forConstructorParameter(null, 0)) - .withMessage("Constructor must not be null"); + .isThrownBy(() -> ResolvableType.forConstructorParameter(null, 0)) + .withMessage("Constructor must not be null"); } @Test @@ -228,8 +228,8 @@ void forMethodParameterByIndex() throws Exception { @Test void forMethodParameterByIndexMustNotBeNull() throws Exception { assertThatIllegalArgumentException() - .isThrownBy(() -> ResolvableType.forMethodParameter(null, 0)) - .withMessage("Method must not be null"); + .isThrownBy(() -> ResolvableType.forMethodParameter(null, 0)) + .withMessage("Method must not be null"); } @Test @@ -268,8 +268,8 @@ void forMethodParameterWithNestingAndLevels() throws Exception { @Test void forMethodParameterMustNotBeNull() throws Exception { assertThatIllegalArgumentException() - .isThrownBy(() -> ResolvableType.forMethodParameter(null)) - .withMessage("MethodParameter must not be null"); + .isThrownBy(() -> ResolvableType.forMethodParameter(null)) + .withMessage("MethodParameter must not be null"); } @Test // SPR-16210 @@ -295,8 +295,8 @@ void forMethodReturn() throws Exception { @Test void forMethodReturnMustNotBeNull() throws Exception { assertThatIllegalArgumentException() - .isThrownBy(() -> ResolvableType.forMethodReturnType(null)) - .withMessage("Method must not be null"); + .isThrownBy(() -> ResolvableType.forMethodReturnType(null)) + .withMessage("Method must not be null"); } @Test @@ -343,7 +343,7 @@ void getComponentTypeForClassArray() throws Exception { ResolvableType type = ResolvableType.forField(field); assertThat(type.isArray()).isTrue(); assertThat(type.getComponentType().getType()) - .isEqualTo(((Class) field.getGenericType()).getComponentType()); + .isEqualTo(((Class) field.getGenericType()).getComponentType()); } @Test @@ -535,7 +535,7 @@ void hasGenerics() throws Exception { void getGenericsFromParameterizedType() throws Exception { ResolvableType type = ResolvableType.forClass(List.class, ExtendsList.class); ResolvableType[] generics = type.getGenerics(); - assertThat(generics.length).isEqualTo(1); + assertThat(generics).hasSize(1); assertThat(generics[0].resolve()).isEqualTo(CharSequence.class); } @@ -543,7 +543,7 @@ void getGenericsFromParameterizedType() throws Exception { void getGenericsFromClass() throws Exception { ResolvableType type = ResolvableType.forClass(List.class); ResolvableType[] generics = type.getGenerics(); - assertThat(generics.length).isEqualTo(1); + assertThat(generics).hasSize(1); assertThat(generics[0].getType().toString()).isEqualTo("E"); } @@ -558,7 +558,7 @@ void noGetGenerics() throws Exception { void getResolvedGenerics() throws Exception { ResolvableType type = ResolvableType.forClass(List.class, ExtendsList.class); Class[] generics = type.resolveGenerics(); - assertThat(generics.length).isEqualTo(1); + assertThat(generics).hasSize(1); assertThat(generics[0]).isEqualTo(CharSequence.class); } @@ -686,7 +686,6 @@ void resolveBoundedTypeVariableResult() throws Exception { assertThat(type.resolve()).isEqualTo(CharSequence.class); } - @Test void resolveBoundedTypeVariableWildcardResult() throws Exception { ResolvableType type = ResolvableType.forMethodReturnType(Methods.class.getMethod("boundedTypeVariableWildcardResult")); @@ -701,30 +700,26 @@ void resolveVariableNotFound() throws Exception { @Test void resolveTypeVariableFromSimpleInterfaceType() { - ResolvableType type = ResolvableType.forClass( - MySimpleInterfaceType.class).as(MyInterfaceType.class); + ResolvableType type = ResolvableType.forClass(MySimpleInterfaceType.class).as(MyInterfaceType.class); assertThat(type.resolveGeneric()).isEqualTo(String.class); } @Test void resolveTypeVariableFromSimpleCollectionInterfaceType() { - ResolvableType type = ResolvableType.forClass( - MyCollectionInterfaceType.class).as(MyInterfaceType.class); + ResolvableType type = ResolvableType.forClass(MyCollectionInterfaceType.class).as(MyInterfaceType.class); assertThat(type.resolveGeneric()).isEqualTo(Collection.class); assertThat(type.resolveGeneric(0, 0)).isEqualTo(String.class); } @Test void resolveTypeVariableFromSimpleSuperclassType() { - ResolvableType type = ResolvableType.forClass( - MySimpleSuperclassType.class).as(MySuperclassType.class); + ResolvableType type = ResolvableType.forClass(MySimpleSuperclassType.class).as(MySuperclassType.class); assertThat(type.resolveGeneric()).isEqualTo(String.class); } @Test void resolveTypeVariableFromSimpleCollectionSuperclassType() { - ResolvableType type = ResolvableType.forClass( - MyCollectionSuperclassType.class).as(MySuperclassType.class); + ResolvableType type = ResolvableType.forClass(MyCollectionSuperclassType.class).as(MySuperclassType.class); assertThat(type.resolveGeneric()).isEqualTo(Collection.class); assertThat(type.resolveGeneric(0, 0)).isEqualTo(String.class); } @@ -751,8 +746,7 @@ void resolveTypeVariableFromFieldTypeWithImplementsType() throws Exception { void resolveTypeVariableFromSuperType() throws Exception { ResolvableType type = ResolvableType.forClass(ExtendsList.class); assertThat(type.resolve()).isEqualTo(ExtendsList.class); - assertThat(type.asCollection().resolveGeneric()) - .isEqualTo(CharSequence.class); + assertThat(type.asCollection().resolveGeneric()).isEqualTo(CharSequence.class); } @Test @@ -964,8 +958,8 @@ void resolveFromClassWithGenerics() throws Exception { @Test void isAssignableFromMustNotBeNull() throws Exception { assertThatIllegalArgumentException() - .isThrownBy(() -> ResolvableType.forClass(Object.class).isAssignableFrom((ResolvableType) null)) - .withMessage("ResolvableType must not be null"); + .isThrownBy(() -> ResolvableType.forClass(Object.class).isAssignableFrom((ResolvableType) null)) + .withMessage("ResolvableType must not be null"); } @Test @@ -1004,6 +998,7 @@ void isAssignableFromForClassAndClass() throws Exception { void isAssignableFromCannotBeResolved() throws Exception { ResolvableType objectType = ResolvableType.forClass(Object.class); ResolvableType unresolvableVariable = ResolvableType.forField(AssignmentBase.class.getField("o")); + assertThat(unresolvableVariable.resolve()).isNull(); assertThatResolvableType(objectType).isAssignableFrom(unresolvableVariable); assertThatResolvableType(unresolvableVariable).isAssignableFrom(objectType); @@ -1220,9 +1215,9 @@ void classWithGenericsAs() throws Exception { @Test void forClassWithMismatchedGenerics() throws Exception { assertThatIllegalArgumentException() - .isThrownBy(() -> ResolvableType.forClassWithGenerics(Map.class, Integer.class)) - .withMessageContaining("Mismatched number of generics specified for") - .withMessageContaining("java.util.Map"); + .isThrownBy(() -> ResolvableType.forClassWithGenerics(Map.class, Integer.class)) + .withMessageContaining("Mismatched number of generics specified for") + .withMessageContaining("java.util.Map"); } @Test @@ -1277,7 +1272,7 @@ void hasUnresolvableGenericsWhenSelfNotResolvable() throws Exception { } @Test - void hasUnresolvableGenericsWhenImplementesRawInterface() throws Exception { + void hasUnresolvableGenericsWhenImplementingRawInterface() throws Exception { ResolvableType type = ResolvableType.forClass(MySimpleInterfaceTypeWithImplementsRaw.class); for (ResolvableType generic : type.getGenerics()) { assertThat(generic.resolve()).isNotNull(); @@ -1307,7 +1302,7 @@ void spr12701() throws Exception { Type type = resolvableType.getType(); assertThat(type).isInstanceOf(ParameterizedType.class); assertThat(((ParameterizedType) type).getRawType()).isEqualTo(Callable.class); - assertThat(((ParameterizedType) type).getActualTypeArguments().length).isEqualTo(1); + assertThat(((ParameterizedType) type).getActualTypeArguments()).hasSize(1); assertThat(((ParameterizedType) type).getActualTypeArguments()[0]).isEqualTo(String.class); }