From e41d8651938a88be16743a7dc0fbd9f8b8ac0be9 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Sun, 9 Jan 2022 16:41:45 +0100 Subject: [PATCH 1/2] Polishing --- .../springframework/core/ResolvableType.java | 30 +++--- .../core/ResolvableTypeTests.java | 98 +++++++++---------- 2 files changed, 64 insertions(+), 64 deletions(-) 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 ae6fe4f0846..d976d99d5b0 100644 --- a/spring-core/src/main/java/org/springframework/core/ResolvableType.java +++ b/spring-core/src/main/java/org/springframework/core/ResolvableType.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2022 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. @@ -48,11 +48,11 @@ import org.springframework.util.StringUtils; * {@link #getGeneric(int...) generic parameters} along with the ability to ultimately * {@link #resolve() resolve} to a {@link java.lang.Class}. * - *

{@code ResolvableTypes} may be obtained from {@link #forField(Field) fields}, - * {@link #forMethodParameter(Method, int) method parameters}, - * {@link #forMethodReturnType(Method) method returns} or - * {@link #forClass(Class) classes}. Most methods on this class will themselves return - * {@link ResolvableType ResolvableTypes}, allowing easy navigation. For example: + *

A {@code ResolvableType} may be obtained from a {@linkplain #forField(Field) field}, + * a {@linkplain #forMethodParameter(Method, int) method parameter}, + * a {@linkplain #forMethodReturnType(Method) method return type}, or a + * {@linkplain #forClass(Class) class}. Most methods on this class will themselves return + * a {@code ResolvableType}, allowing for easy navigation. For example: *

  * private HashMap<Integer, List<String>> myMap;
  *
@@ -182,7 +182,7 @@ public class ResolvableType implements Serializable {
 
 	/**
 	 * Private constructor used to create a new {@link ResolvableType} on a {@link Class} basis.
-	 * Avoids all {@code instanceof} checks in order to create a straight {@link Class} wrapper.
+	 * 

Avoids all {@code instanceof} checks in order to create a straight {@link Class} wrapper. * @since 4.2 */ private ResolvableType(@Nullable Class clazz) { @@ -406,7 +406,7 @@ public class ResolvableType implements Serializable { /** * Convenience method to return this type as a resolvable {@link Collection} type. - * Returns {@link #NONE} if this type does not implement or extend + *

Returns {@link #NONE} if this type does not implement or extend * {@link Collection}. * @see #as(Class) * @see #asMap() @@ -417,7 +417,7 @@ public class ResolvableType implements Serializable { /** * Convenience method to return this type as a resolvable {@link Map} type. - * Returns {@link #NONE} if this type does not implement or extend + *

Returns {@link #NONE} if this type does not implement or extend * {@link Map}. * @see #as(Class) * @see #asCollection() @@ -458,7 +458,7 @@ public class ResolvableType implements Serializable { /** * Return a {@link ResolvableType} representing the direct supertype of this type. - * If no supertype is available this method returns {@link #NONE}. + *

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

Note: The resulting {@link ResolvableType} instance may not be {@link Serializable}. * @see #getInterfaces() */ @@ -608,7 +608,7 @@ public class ResolvableType implements Serializable { /** * Return a {@link ResolvableType} for the specified nesting level. - * See {@link #getNested(int, Map)} for details. + *

See {@link #getNested(int, Map)} for details. * @param nestingLevel the nesting level * @return the {@link ResolvableType} type, or {@code #NONE} */ @@ -999,7 +999,7 @@ public class ResolvableType implements Serializable { /** * Return a {@link ResolvableType} for the specified {@link Class}, * using the full generic type information for assignability checks. - * For example: {@code ResolvableType.forClass(MyArrayList.class)}. + *

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 @@ -1014,7 +1014,7 @@ public class ResolvableType implements Serializable { * Return a {@link 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)}. + *

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 @@ -1043,7 +1043,7 @@ public class ResolvableType implements Serializable { /** * Return a {@link ResolvableType} for the specified base type * (interface or base class) with a given implementation class. - * For example: {@code ResolvableType.forClass(List.class, MyArrayList.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 @@ -1238,7 +1238,7 @@ public class ResolvableType implements Serializable { /** * Return a {@link ResolvableType} for the specified {@link Method} return type. - * Use this variant when the class that declares the method includes generic + *

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 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 3ca17918b53..c153c883860 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-2021 the original author or authors. + * Copyright 2002-2022 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. @@ -83,19 +83,19 @@ class ResolvableTypeTests { assertThat(none.asMap()).isEqualTo(ResolvableType.NONE); assertThat(none.getComponentType()).isEqualTo(ResolvableType.NONE); assertThat(none.getGeneric(0)).isEqualTo(ResolvableType.NONE); - assertThat(none.getGenerics().length).isEqualTo(0); - assertThat(none.getInterfaces().length).isEqualTo(0); + assertThat(none.getGenerics()).isEmpty(); + assertThat(none.getInterfaces()).isEmpty(); assertThat(none.getSuperType()).isEqualTo(ResolvableType.NONE); assertThat(none.getType()).isEqualTo(ResolvableType.EmptyType.INSTANCE); - assertThat(none.hasGenerics()).isEqualTo(false); - assertThat(none.isArray()).isEqualTo(false); + assertThat(none.hasGenerics()).isFalse(); + assertThat(none.isArray()).isFalse(); assertThat(none.resolve()).isNull(); assertThat(none.resolve(String.class)).isEqualTo(String.class); assertThat(none.resolveGeneric(0)).isNull(); - assertThat(none.resolveGenerics().length).isEqualTo(0); + assertThat(none.resolveGenerics()).isEmpty(); assertThat(none.toString()).isEqualTo("?"); - assertThat(none.hasUnresolvableGenerics()).isEqualTo(false); - assertThat(none.isAssignableFrom(ResolvableType.forClass(Object.class))).isEqualTo(false); + assertThat(none.hasUnresolvableGenerics()).isFalse(); + assertThat(none.isAssignableFrom(ResolvableType.forClass(Object.class))).isFalse(); } @Test @@ -148,9 +148,9 @@ class ResolvableTypeTests { @Test void forInstanceMustNotBeNull() throws Exception { - assertThatIllegalArgumentException().isThrownBy(() -> - ResolvableType.forInstance(null)) - .withMessageContaining("Instance must not be null"); + assertThatIllegalArgumentException() + .isThrownBy(() -> ResolvableType.forInstance(null)) + .withMessage("Instance must not be null"); } @Test @@ -201,9 +201,9 @@ class ResolvableTypeTests { @Test void forFieldMustNotBeNull() throws Exception { - assertThatIllegalArgumentException().isThrownBy(() -> - ResolvableType.forField(null)) - .withMessageContaining("Field must not be null"); + assertThatIllegalArgumentException() + .isThrownBy(() -> ResolvableType.forField(null)) + .withMessage("Field must not be null"); } @Test @@ -215,9 +215,9 @@ class ResolvableTypeTests { @Test void forConstructorParameterMustNotBeNull() throws Exception { - assertThatIllegalArgumentException().isThrownBy(() -> - ResolvableType.forConstructorParameter(null, 0)) - .withMessageContaining("Constructor must not be null"); + assertThatIllegalArgumentException() + .isThrownBy(() -> ResolvableType.forConstructorParameter(null, 0)) + .withMessage("Constructor must not be null"); } @Test @@ -229,9 +229,9 @@ class ResolvableTypeTests { @Test void forMethodParameterByIndexMustNotBeNull() throws Exception { - assertThatIllegalArgumentException().isThrownBy(() -> - ResolvableType.forMethodParameter(null, 0)) - .withMessageContaining("Method must not be null"); + assertThatIllegalArgumentException() + .isThrownBy(() -> ResolvableType.forMethodParameter(null, 0)) + .withMessage("Method must not be null"); } @Test @@ -269,9 +269,9 @@ class ResolvableTypeTests { @Test void forMethodParameterMustNotBeNull() throws Exception { - assertThatIllegalArgumentException().isThrownBy(() -> - ResolvableType.forMethodParameter(null)) - .withMessageContaining("MethodParameter must not be null"); + assertThatIllegalArgumentException() + .isThrownBy(() -> ResolvableType.forMethodParameter(null)) + .withMessage("MethodParameter must not be null"); } @Test // SPR-16210 @@ -296,9 +296,9 @@ class ResolvableTypeTests { @Test void forMethodReturnMustNotBeNull() throws Exception { - assertThatIllegalArgumentException().isThrownBy(() -> - ResolvableType.forMethodReturnType(null)) - .withMessageContaining("Method must not be null"); + assertThatIllegalArgumentException() + .isThrownBy(() -> ResolvableType.forMethodReturnType(null)) + .withMessage("Method must not be null"); } @Test @@ -317,7 +317,7 @@ class ResolvableTypeTests { void arrayClassType() throws Exception { ResolvableType type = ResolvableType.forField(Fields.class.getField("arrayClassType")); assertThat(type.getType()).isInstanceOf(Class.class); - assertThat(((Class) type.getType()).isArray()).isEqualTo(true); + assertThat(((Class) type.getType()).isArray()).isTrue(); } @Test @@ -343,7 +343,7 @@ class ResolvableTypeTests { void getComponentTypeForClassArray() throws Exception { Field field = Fields.class.getField("arrayClassType"); ResolvableType type = ResolvableType.forField(field); - assertThat(type.isArray()).isEqualTo(true); + assertThat(type.isArray()).isTrue(); assertThat(type.getComponentType().getType()) .isEqualTo(((Class) field.getGenericType()).getComponentType()); } @@ -351,7 +351,7 @@ class ResolvableTypeTests { @Test void getComponentTypeForGenericArrayType() throws Exception { ResolvableType type = ResolvableType.forField(Fields.class.getField("genericArrayType")); - assertThat(type.isArray()).isEqualTo(true); + assertThat(type.isArray()).isTrue(); assertThat(type.getComponentType().getType()).isEqualTo( ((GenericArrayType) type.getType()).getGenericComponentType()); } @@ -359,7 +359,7 @@ class ResolvableTypeTests { @Test void getComponentTypeForVariableThatResolvesToGenericArray() throws Exception { ResolvableType type = ResolvableType.forClass(ListOfGenericArray.class).asCollection().getGeneric(); - assertThat(type.isArray()).isEqualTo(true); + assertThat(type.isArray()).isTrue(); assertThat(type.getType()).isInstanceOf(TypeVariable.class); assertThat(type.getComponentType().getType().toString()).isEqualTo( "java.util.List"); @@ -368,7 +368,7 @@ class ResolvableTypeTests { @Test void getComponentTypeForNonArray() throws Exception { ResolvableType type = ResolvableType.forClass(String.class); - assertThat(type.isArray()).isEqualTo(false); + assertThat(type.isArray()).isFalse(); assertThat(type.getComponentType()).isEqualTo(ResolvableType.NONE); } @@ -438,7 +438,7 @@ class ResolvableTypeTests { @Test void getInterfaces() throws Exception { ResolvableType type = ResolvableType.forClass(ExtendsList.class); - assertThat(type.getInterfaces().length).isEqualTo(0); + assertThat(type.getInterfaces()).isEmpty(); SortedSet interfaces = new TreeSet<>(); for (ResolvableType interfaceType : type.getSuperType().getInterfaces()) { interfaces.add(interfaceType.toString()); @@ -529,8 +529,8 @@ class ResolvableTypeTests { @Test void hasGenerics() throws Exception { ResolvableType type = ResolvableType.forClass(ExtendsList.class); - assertThat(type.hasGenerics()).isEqualTo(false); - assertThat(type.asCollection().hasGenerics()).isEqualTo(true); + assertThat(type.hasGenerics()).isFalse(); + assertThat(type.asCollection().hasGenerics()).isTrue(); } @Test @@ -553,7 +553,7 @@ class ResolvableTypeTests { void noGetGenerics() throws Exception { ResolvableType type = ResolvableType.forClass(ExtendsList.class); ResolvableType[] generics = type.getGenerics(); - assertThat(generics.length).isEqualTo(0); + assertThat(generics).isEmpty(); } @Test @@ -602,7 +602,7 @@ class ResolvableTypeTests { ResolvableType type = ResolvableType.forField(Fields.class.getField("stringArrayList")); ResolvableType generic = type.asCollection().getGeneric(); assertThat(generic.getType().toString()).isEqualTo("E"); - assertThat(generic.isArray()).isEqualTo(true); + assertThat(generic.isArray()).isTrue(); assertThat(generic.resolve()).isEqualTo(String[].class); } @@ -610,7 +610,7 @@ class ResolvableTypeTests { void resolveVariableGenericArray() throws Exception { ResolvableType type = ResolvableType.forField(Fields.class.getField("variableTypeGenericArray"), TypedFields.class); assertThat(type.getType().toString()).isEqualTo("T[]"); - assertThat(type.isArray()).isEqualTo(true); + assertThat(type.isArray()).isTrue(); assertThat(type.resolve()).isEqualTo(String[].class); } @@ -618,7 +618,7 @@ class ResolvableTypeTests { void resolveVariableGenericArrayUnknown() throws Exception { ResolvableType type = ResolvableType.forField(Fields.class.getField("variableTypeGenericArray")); assertThat(type.getType().toString()).isEqualTo("T[]"); - assertThat(type.isArray()).isEqualTo(true); + assertThat(type.isArray()).isTrue(); assertThat(type.resolve()).isNull(); } @@ -626,7 +626,7 @@ class ResolvableTypeTests { void resolveVariableGenericArrayUnknownWithFallback() throws Exception { ResolvableType type = ResolvableType.forField(Fields.class.getField("variableTypeGenericArray")); assertThat(type.getType().toString()).isEqualTo("T[]"); - assertThat(type.isArray()).isEqualTo(true); + assertThat(type.isArray()).isTrue(); assertThat(type.toClass()).isEqualTo(Object.class); } @@ -965,16 +965,16 @@ class ResolvableTypeTests { @Test void isAssignableFromMustNotBeNull() throws Exception { - assertThatIllegalArgumentException().isThrownBy(() -> - ResolvableType.forClass(Object.class).isAssignableFrom((ResolvableType) null)) - .withMessageContaining("Type must not be null"); + assertThatIllegalArgumentException() + .isThrownBy(() -> ResolvableType.forClass(Object.class).isAssignableFrom((ResolvableType) null)) + .withMessage("ResolvableType must not be null"); } @Test void isAssignableFromForNone() throws Exception { ResolvableType objectType = ResolvableType.forClass(Object.class); - assertThat(objectType.isAssignableFrom(ResolvableType.NONE)).isEqualTo(false); - assertThat(ResolvableType.NONE.isAssignableFrom(objectType)).isEqualTo(false); + assertThat(objectType.isAssignableFrom(ResolvableType.NONE)).isFalse(); + assertThat(ResolvableType.NONE.isAssignableFrom(objectType)).isFalse(); } @Test @@ -1262,19 +1262,19 @@ class ResolvableTypeTests { @Test void hasUnresolvableGenerics() throws Exception { ResolvableType type = ResolvableType.forField(Fields.class.getField("stringList")); - assertThat(type.hasUnresolvableGenerics()).isEqualTo(false); + assertThat(type.hasUnresolvableGenerics()).isFalse(); } @Test void hasUnresolvableGenericsBasedOnOwnGenerics() throws Exception { ResolvableType type = ResolvableType.forClass(List.class); - assertThat(type.hasUnresolvableGenerics()).isEqualTo(true); + assertThat(type.hasUnresolvableGenerics()).isTrue(); } @Test void hasUnresolvableGenericsWhenSelfNotResolvable() throws Exception { ResolvableType type = ResolvableType.forClass(List.class).getGeneric(); - assertThat(type.hasUnresolvableGenerics()).isEqualTo(false); + assertThat(type.hasUnresolvableGenerics()).isFalse(); } @Test @@ -1283,7 +1283,7 @@ class ResolvableTypeTests { for (ResolvableType generic : type.getGenerics()) { assertThat(generic.resolve()).isNotNull(); } - assertThat(type.hasUnresolvableGenerics()).isEqualTo(true); + assertThat(type.hasUnresolvableGenerics()).isTrue(); } @Test @@ -1292,7 +1292,7 @@ class ResolvableTypeTests { for (ResolvableType generic : type.getGenerics()) { assertThat(generic.resolve()).isNotNull(); } - assertThat(type.hasUnresolvableGenerics()).isEqualTo(true); + assertThat(type.hasUnresolvableGenerics()).isTrue(); } @Test From 8087eb69bfc2782bd8c5b81c57d63c849b87ed8c Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Sun, 9 Jan 2022 16:55:17 +0100 Subject: [PATCH 2/2] Improve error message in ResolvableType.forClassWithGenerics() Prior to this commit, the error message generated for a mismatched number of generics did not include the information about the class in question. This commit improves the error message by providing more context, specifically the result of invoking toGenericString() on the class. For example, instead of throwing an IllegalArgumentException with the error message "Mismatched number of generics specified", the error message would now be "Mismatched number of generics specified for public abstract interface java.util.Map". Closes gh-27847 --- .../main/java/org/springframework/core/ResolvableType.java | 2 +- .../java/org/springframework/core/ResolvableTypeTests.java | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) 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 d976d99d5b0..6ba088cfd1e 100644 --- a/spring-core/src/main/java/org/springframework/core/ResolvableType.java +++ b/spring-core/src/main/java/org/springframework/core/ResolvableType.java @@ -1085,7 +1085,7 @@ public class ResolvableType implements Serializable { Assert.notNull(clazz, "Class must not be null"); Assert.notNull(generics, "Generics array must not be null"); TypeVariable[] variables = clazz.getTypeParameters(); - Assert.isTrue(variables.length == generics.length, "Mismatched number of generics specified"); + Assert.isTrue(variables.length == generics.length, () -> "Mismatched number of generics specified for " + clazz.toGenericString()); Type[] arguments = new Type[generics.length]; for (int i = 0; i < generics.length; i++) { 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 c153c883860..71b17e0da02 100644 --- a/spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java +++ b/spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java @@ -1221,9 +1221,10 @@ class ResolvableTypeTests { @Test void forClassWithMismatchedGenerics() throws Exception { - assertThatIllegalArgumentException().isThrownBy(() -> - ResolvableType.forClassWithGenerics(Map.class, Integer.class)) - .withMessageContaining("Mismatched number of generics specified"); + assertThatIllegalArgumentException() + .isThrownBy(() -> ResolvableType.forClassWithGenerics(Map.class, Integer.class)) + .withMessageContaining("Mismatched number of generics specified for") + .withMessageContaining("java.util.Map"); } @Test