From b01fdb01408499bf9c73de1e927017b4870ffe26 Mon Sep 17 00:00:00 2001 From: Junseo Bae Date: Wed, 1 Apr 2026 00:54:39 +0900 Subject: [PATCH] Fix ClassFileMethodMetadata return type names for primitives and arrays Return correct names for primitive and array types Introduce resolveTypeName helper for ClassDesc handling Add ClassFileMethodMetadataTests (java24Test) Extend AbstractMethodMetadataTests with void return case See gh-36577 Signed-off-by: Junseo Bae --- .../classreading/ClassFileMethodMetadata.java | 14 +++- .../type/AbstractMethodMetadataTests.java | 12 +++ .../ClassFileMethodMetadataTests.java | 81 +++++++++++++++++++ 3 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 spring-core/src/test/java24/org/springframework/core/type/classreading/ClassFileMethodMetadataTests.java diff --git a/spring-core/src/main/java24/org/springframework/core/type/classreading/ClassFileMethodMetadata.java b/spring-core/src/main/java24/org/springframework/core/type/classreading/ClassFileMethodMetadata.java index bc61f08101a..76d36f4b3d8 100644 --- a/spring-core/src/main/java24/org/springframework/core/type/classreading/ClassFileMethodMetadata.java +++ b/spring-core/src/main/java24/org/springframework/core/type/classreading/ClassFileMethodMetadata.java @@ -143,7 +143,7 @@ final class ClassFileMethodMetadata implements MethodMetadata { AccessFlags flags = methodModel.flags(); String declaringClassName = methodModel.parent().map(parent -> ClassUtils.convertResourcePathToClassName(parent.thisClass().name().stringValue())).orElse(null); ClassDesc returnType = methodModel.methodTypeSymbol().returnType(); - String returnTypeName = returnType.packageName() + "." + returnType.displayName(); + String returnTypeName = resolveTypeName(returnType); Source source = new Source(declaringClassName, flags, methodName, methodModel.methodTypeSymbol()); MergedAnnotations annotations = methodModel.elementStream() .filter(element -> element instanceof RuntimeVisibleAnnotationsAttribute) @@ -154,6 +154,18 @@ final class ClassFileMethodMetadata implements MethodMetadata { } + private static String resolveTypeName(ClassDesc type) { + if (type.isPrimitive()) { + return type.displayName(); + } + if (type.isArray()) { + return resolveTypeName(type.componentType()) + "[]"; + } + String packageName = type.packageName(); + return (packageName.isEmpty() ? type.displayName() : packageName + "." + type.displayName()); + } + + /** * {@link MergedAnnotation} source. * @param declaringClassName the name of the declaring class 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 4d52c7f4494..26c14b3159b 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 @@ -102,6 +102,11 @@ public abstract class AbstractMethodMetadataTests { String.class.getName()); } + @Test + void getReturnTypeReturnsVoidForVoidReturnType() { + assertThat(getTagged(WithVoidMethod.class).getReturnTypeName()).isEqualTo("void"); + } + @Test void isAbstractWhenAbstractReturnsTrue() { assertThat(getTagged(WithAbstractMethod.class).isAbstract()).isTrue(); @@ -217,6 +222,13 @@ public abstract class AbstractMethodMetadataTests { } + public static class WithVoidMethod { + + @Tag + public void test() {} + + } + public static class WithMethodWithOneArgument { @Tag diff --git a/spring-core/src/test/java24/org/springframework/core/type/classreading/ClassFileMethodMetadataTests.java b/spring-core/src/test/java24/org/springframework/core/type/classreading/ClassFileMethodMetadataTests.java new file mode 100644 index 00000000000..23b97019054 --- /dev/null +++ b/spring-core/src/test/java24/org/springframework/core/type/classreading/ClassFileMethodMetadataTests.java @@ -0,0 +1,81 @@ +package org.springframework.core.type.classreading; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import org.junit.jupiter.api.Test; + +import org.springframework.core.type.MethodMetadata; + +import static org.assertj.core.api.Assertions.assertThat; + +class ClassFileMethodMetadataTests { + + @Test + void getReturnTypeReturnsVoidForVoidReturnType() throws Exception { + MethodMetadata metadata = new ClassFileMetadataReaderFactory(getClass().getClassLoader()) + .getMetadataReader(WithVoidMethod.class.getName()) + .getAnnotationMetadata() + .getAnnotatedMethods(Tag.class.getName()) + .iterator().next(); + + assertThat(metadata.getReturnTypeName()).isEqualTo("void"); + } + + @Test + void getReturnTypeReturnsPrimitiveForPrimitiveReturnType() throws Exception { + MethodMetadata metadata = new ClassFileMetadataReaderFactory(getClass().getClassLoader()) + .getMetadataReader(WithIntMethod.class.getName()) + .getAnnotationMetadata() + .getAnnotatedMethods(Tag.class.getName()) + .iterator().next(); + + assertThat(metadata.getReturnTypeName()).isEqualTo("int"); + } + + @Test + void getReturnTypeReturnsReferenceTypeForReferenceReturnType() throws Exception { + MethodMetadata metadata = new ClassFileMetadataReaderFactory(getClass().getClassLoader()) + .getMetadataReader(WithStringMethod.class.getName()) + .getAnnotationMetadata() + .getAnnotatedMethods(Tag.class.getName()) + .iterator().next(); + + assertThat(metadata.getReturnTypeName()).isEqualTo(String.class.getName()); + } + + @Test + void getReturnTypeReturnsArrayTypeForArrayReturnType() throws Exception { + MethodMetadata metadata = new ClassFileMetadataReaderFactory(getClass().getClassLoader()) + .getMetadataReader(WithStringArrayMethod.class.getName()) + .getAnnotationMetadata() + .getAnnotatedMethods(Tag.class.getName()) + .iterator().next(); + + assertThat(metadata.getReturnTypeName()).isEqualTo("java.lang.String[]"); + } + + @Retention(RetentionPolicy.RUNTIME) + @interface Tag {} + + public static class WithVoidMethod { + @Tag + public void test() {} + } + + public static class WithIntMethod { + @Tag + public int test() { return 0; } + } + + public static class WithStringMethod { + @Tag + public String test() { return ""; } + } + + public static class WithStringArrayMethod { + @Tag + public String[] test() { return new String[0]; } + } + +}