From 5b3063cc013912ba26f544cce7948fe69735a300 Mon Sep 17 00:00:00 2001 From: sunnyboy33 Date: Tue, 7 Jul 2026 14:57:25 +0900 Subject: [PATCH 1/2] Introduce Parameter-based factory methods in TypeDescriptor Signed-off-by: sunnyboy33 --- .../core/convert/TypeDescriptor.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/spring-core/src/main/java/org/springframework/core/convert/TypeDescriptor.java b/spring-core/src/main/java/org/springframework/core/convert/TypeDescriptor.java index 57ddf078df9b..4b1f0457d8e1 100644 --- a/spring-core/src/main/java/org/springframework/core/convert/TypeDescriptor.java +++ b/spring-core/src/main/java/org/springframework/core/convert/TypeDescriptor.java @@ -19,6 +19,7 @@ import java.io.Serializable; import java.lang.annotation.Annotation; import java.lang.reflect.Field; +import java.lang.reflect.Parameter; import java.lang.reflect.Type; import java.util.Arrays; import java.util.Collection; @@ -548,6 +549,18 @@ public String toString() { } + /** + * Create a new type descriptor for the specified {@link Parameter}. + *

This is a convenience factory method for scenarios where a {@code Parameter} + * descriptor is already available. + * @param parameter the source parameter + * @return the corresponding type descriptor + * @since 7.1 + */ + public static TypeDescriptor forParameter(Parameter parameter) { + return new TypeDescriptor(MethodParameter.forParameter(parameter)); + } + /** * Create a new type descriptor for an object. *

Use this factory method to introspect a source object before asking the @@ -676,6 +689,32 @@ public static TypeDescriptor map(Class mapType, @Nullable TypeDescriptor keyT return new TypeDescriptor(methodParameter).nested(nestingLevel); } + /** + * Create a type descriptor for a nested type declared within the parameter. + *

For example, if the parameter is a {@code List} and the + * nesting level is 1, the nested type descriptor will be {@code String.class}. + *

If the parameter is a {@code List>} and the nesting + * level is 2, the nested type descriptor will also be a {@code String.class}. + *

If the parameter is a {@code Map} and the nesting + * level is 1, the nested type descriptor will be String, derived from the map value. + *

If the parameter is a {@code List>} and the + * nesting level is 2, the nested type descriptor will be String, derived from the map value. + *

Returns {@code null} if a nested type cannot be obtained because it was not declared. + * For example, if the parameter is a {@code List}, the nested type + * descriptor returned will be {@code null}. + * @param parameter the parameter + * @param nestingLevel the nesting level of the collection/array element or + * map key/value declaration within the parameter + * @return the nested type descriptor at the specified nesting level, + * or {@code null} if it could not be obtained + * @throws IllegalArgumentException if the types up to the specified nesting + * level are not of collection, array, or map types + * @since 7.1 + */ + public static @Nullable TypeDescriptor nested(Parameter parameter, int nestingLevel) { + return new TypeDescriptor(MethodParameter.forParameter(parameter)).nested(nestingLevel); + } + /** * Create a type descriptor for a nested type declared within the field. *

For example, if the field is a {@code List} and the nesting From b8d86584626aa3c5e925f76ebc2f56785fa6f38b Mon Sep 17 00:00:00 2001 From: sunnyboy33 Date: Tue, 7 Jul 2026 15:05:04 +0900 Subject: [PATCH 2/2] Add unit tests for Parameter-based TypeDescriptor factory methods Signed-off-by: sunnyboy33 --- .../core/convert/TypeDescriptorTests.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/spring-core/src/test/java/org/springframework/core/convert/TypeDescriptorTests.java b/spring-core/src/test/java/org/springframework/core/convert/TypeDescriptorTests.java index 2554391af6e6..9811a88a3dde 100644 --- a/spring-core/src/test/java/org/springframework/core/convert/TypeDescriptorTests.java +++ b/spring-core/src/test/java/org/springframework/core/convert/TypeDescriptorTests.java @@ -26,6 +26,8 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; import java.util.ArrayList; import java.util.Collection; import java.util.Date; @@ -86,6 +88,36 @@ void parameterScalar() throws Exception { assertThat(desc.isMap()).isFalse(); } + @Test + void forParameter() throws Exception { + Method method = getClass().getMethod("testParameterScalar", String.class); + Parameter parameter = method.getParameters()[0]; + TypeDescriptor desc = TypeDescriptor.forParameter(parameter); + assertThat(desc.getType()).isEqualTo(String.class); + } + + @Test + void forParameterMustNotBeNull() { + assertThatIllegalArgumentException() + .isThrownBy(() -> TypeDescriptor.forParameter(null)) + .withMessage("Parameter must not be null"); + } + + @Test + void nestedParameter() throws Exception { + Method method = getClass().getMethod("test2", List.class); + Parameter parameter = method.getParameters()[0]; + TypeDescriptor desc = TypeDescriptor.nested(parameter, 2); + assertThat(desc.getType()).isEqualTo(String.class); + } + + @Test + void nestedParameterMustNotBeNull() { + assertThatIllegalArgumentException() + .isThrownBy(() -> TypeDescriptor.nested((Parameter) null, 2)) + .withMessage("Parameter must not be null"); + } + @Test void parameterList() throws Exception { MethodParameter methodParameter = new MethodParameter(getClass().getMethod("testParameterList", List.class), 0);