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
This commit is contained in:
Sam Brannen
2026-04-08 10:27:12 +02:00
parent c4c0aca69b
commit 62c6d67615
3 changed files with 24 additions and 36 deletions
@@ -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();
@@ -103,7 +103,7 @@ public class StandardMethodMetadata implements MethodMetadata {
@Override
public String getReturnTypeName() {
return this.introspectedMethod.getReturnType().getName();
return this.introspectedMethod.getReturnType().getTypeName();
}
@Override
@@ -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