From 62c6d67615cdb4c31092de339f5ba0c3df2057cd Mon Sep 17 00:00:00 2001 From: Sam Brannen <104798+sbrannen@users.noreply.github.com> Date: Wed, 8 Apr 2026 10:27:12 +0200 Subject: [PATCH] Align StandardMethodMetadata with ASM/ClassFile support for getReturnTypeName() We currently have three implementations of MethodMetadata: - StandardMethodMetadata (Java reflection) - SimpleMethodMetadata (ASM) - ClassFileMethodMetadata (ClassFile API) The ASM and ClassFile variants return a string equivalent to Class#getTypeName(); whereas, StandardMethodMetadata currently returns a binary name using Class#getName() (for example, `[I` instead of `int[]`). In order to align with the ASM and ClassFile variants and provide consistent results for all MethodMetadata implementations, this commit revises StandardMethodMetadata.getReturnTypeName() to use Class#getTypeName(). Closes gh-36619 --- .../core/type/MethodMetadata.java | 1 + .../core/type/StandardMethodMetadata.java | 2 +- .../type/AbstractMethodMetadataTests.java | 57 +++++++------------ 3 files changed, 24 insertions(+), 36 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/core/type/MethodMetadata.java b/spring-core/src/main/java/org/springframework/core/type/MethodMetadata.java index 51800ce9871..5451c503698 100644 --- a/spring-core/src/main/java/org/springframework/core/type/MethodMetadata.java +++ b/spring-core/src/main/java/org/springframework/core/type/MethodMetadata.java @@ -54,6 +54,7 @@ public interface MethodMetadata extends AnnotatedTypeMetadata { /** * Get the fully-qualified name of the underlying method's declared return type. * @since 4.2 + * @see Class#getTypeName() */ String getReturnTypeName(); diff --git a/spring-core/src/main/java/org/springframework/core/type/StandardMethodMetadata.java b/spring-core/src/main/java/org/springframework/core/type/StandardMethodMetadata.java index 4a099c384a1..1cb2f20cdeb 100644 --- a/spring-core/src/main/java/org/springframework/core/type/StandardMethodMetadata.java +++ b/spring-core/src/main/java/org/springframework/core/type/StandardMethodMetadata.java @@ -103,7 +103,7 @@ public class StandardMethodMetadata implements MethodMetadata { @Override public String getReturnTypeName() { - return this.introspectedMethod.getReturnType().getName(); + return this.introspectedMethod.getReturnType().getTypeName(); } @Override diff --git a/spring-core/src/test/java/org/springframework/core/type/AbstractMethodMetadataTests.java b/spring-core/src/test/java/org/springframework/core/type/AbstractMethodMetadataTests.java index 97547e824b9..6d95c2466ad 100644 --- a/spring-core/src/test/java/org/springframework/core/type/AbstractMethodMetadataTests.java +++ b/spring-core/src/test/java/org/springframework/core/type/AbstractMethodMetadataTests.java @@ -30,7 +30,6 @@ import org.springframework.util.MultiValueMap; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.entry; -import static org.assertj.core.api.Assumptions.assumeThat; /** * Base class for {@link MethodMetadata} tests. @@ -81,6 +80,10 @@ public abstract class AbstractMethodMetadataTests { assertThat(getTagged(WithMethod.class).toString()) .isEqualTo("public java.lang.String " + WithMethod.class.getName() + ".test()"); + assertThat(getTagged(WithMethodWithLocalType.class).toString()) + .isEqualTo("public org.springframework.core.type.AbstractMethodMetadataTests$LocalType " + + WithMethodWithLocalType.class.getName() + ".test()"); + assertThat(getTagged(WithMethodWithOneArgument.class).toString()) .isEqualTo("public java.lang.String " + WithMethodWithOneArgument.class.getName() + ".test(java.lang.String)"); @@ -111,8 +114,13 @@ public abstract class AbstractMethodMetadataTests { } @Test - void getReturnTypeReturnsReturnType() { - assertThat(getTagged(WithMethod.class).getReturnTypeName()).isEqualTo(String.class.getName()); + void getReturnTypeReturnsTypeName() { + assertThat(getTagged(WithMethod.class).getReturnTypeName()).isEqualTo(String.class.getTypeName()); + } + + @Test + void getReturnTypeReturnsTypeNameForLocalType() { + assertThat(getTagged(WithMethodWithLocalType.class).getReturnTypeName()).isEqualTo(LocalType.class.getTypeName()); } @Test @@ -120,59 +128,27 @@ public abstract class AbstractMethodMetadataTests { assertThat(getTagged(WithVoidMethod.class).getReturnTypeName()).isEqualTo("void"); } - @Test - void getReturnTypeReturnsPrimitiveArrayForPrimitiveArrayReturnTypeForStandardReflection() { - MethodMetadata methodMetadata = getTagged(WithPrimitiveArrayMethod.class); - assumeThat(methodMetadata).as("skipped for ASM and ClassFile").isInstanceOf(StandardMethodMetadata.class); - assertThat(methodMetadata.getReturnTypeName()).isEqualTo("[I"); - } - @Test void getReturnTypeReturnsPrimitiveArrayForPrimitiveArrayReturnType() { MethodMetadata methodMetadata = getTagged(WithPrimitiveArrayMethod.class); - assumeThat(methodMetadata).as("skipped for standard reflection").isNotInstanceOf(StandardMethodMetadata.class); assertThat(methodMetadata.getReturnTypeName()).isEqualTo("int[]"); } - @Test - void getReturnTypeReturnsStringArrayForStringArrayReturnTypeForStandardReflection() { - MethodMetadata methodMetadata = getTagged(WithStringArrayMethod.class); - assumeThat(methodMetadata).as("skipped for ASM and ClassFile").isInstanceOf(StandardMethodMetadata.class); - assertThat(methodMetadata.getReturnTypeName()).isEqualTo("[Ljava.lang.String;"); - } - @Test void getReturnTypeReturnsStringArrayForStringArrayReturnType() { MethodMetadata methodMetadata = getTagged(WithStringArrayMethod.class); - assumeThat(methodMetadata).as("skipped for standard reflection").isNotInstanceOf(StandardMethodMetadata.class); assertThat(methodMetadata.getReturnTypeName()).isEqualTo("java.lang.String[]"); } - @Test - void getReturnTypeReturnsTwoDimensionalPrimitiveArrayForTwoDimensionalPrimitiveArrayReturnTypeForStandardReflection() { - MethodMetadata methodMetadata = getTagged(WithTwoDimensionalPrimitiveArrayMethod.class); - assumeThat(methodMetadata).as("skipped for ASM and ClassFile").isInstanceOf(StandardMethodMetadata.class); - assertThat(methodMetadata.getReturnTypeName()).isEqualTo("[[I"); - } - @Test void getReturnTypeReturnsTwoDimensionalPrimitiveArrayForTwoDimensionalPrimitiveArrayReturnType() { MethodMetadata methodMetadata = getTagged(WithTwoDimensionalPrimitiveArrayMethod.class); - assumeThat(methodMetadata).as("skipped for standard reflection").isNotInstanceOf(StandardMethodMetadata.class); assertThat(methodMetadata.getReturnTypeName()).isEqualTo("int[][]"); } - @Test - void getReturnTypeReturnsTwoDimensionalStringArrayForTwoDimensionalStringArrayReturnTypeForStandardReflection() { - MethodMetadata methodMetadata = getTagged(WithTwoDimensionalStringArrayMethod.class); - assumeThat(methodMetadata).as("skipped for ASM and ClassFile").isInstanceOf(StandardMethodMetadata.class); - assertThat(methodMetadata.getReturnTypeName()).isEqualTo("[[Ljava.lang.String;"); - } - @Test void getReturnTypeReturnsTwoDimensionalStringArrayForTwoDimensionalStringArrayReturnType() { MethodMetadata methodMetadata = getTagged(WithTwoDimensionalStringArrayMethod.class); - assumeThat(methodMetadata).as("skipped for standard reflection").isNotInstanceOf(StandardMethodMetadata.class); assertThat(methodMetadata.getReturnTypeName()).isEqualTo("java.lang.String[][]"); } @@ -293,6 +269,17 @@ public abstract class AbstractMethodMetadataTests { } + public static class LocalType { + } + + public static class WithMethodWithLocalType { + + @Tag + public LocalType test() { + return new LocalType(); + } + } + public static class WithVoidMethod { @Tag