diff --git a/spring-core/src/main/java24/org/springframework/core/type/classreading/ClassFileAnnotationDelegate.java b/spring-core/src/main/java24/org/springframework/core/type/classreading/ClassFileAnnotationDelegate.java index 5bd50610864d..f860c787f5c7 100644 --- a/spring-core/src/main/java24/org/springframework/core/type/classreading/ClassFileAnnotationDelegate.java +++ b/spring-core/src/main/java24/org/springframework/core/type/classreading/ClassFileAnnotationDelegate.java @@ -122,6 +122,46 @@ private static Object parseArrayValue(String className, @Nullable ClassLoader cl case AnnotationValue.OfLong _ -> { return stream.map(AnnotationValue.OfLong.class::cast).mapToLong(AnnotationValue.OfLong::longValue).toArray(); } + case AnnotationValue.OfByte _ -> { + List values = arrayValue.values(); + byte[] result = new byte[values.size()]; + for (int i = 0; i < result.length; i++) { + result[i] = ((AnnotationValue.OfByte) values.get(i)).byteValue(); + } + return result; + } + case AnnotationValue.OfShort _ -> { + List values = arrayValue.values(); + short[] result = new short[values.size()]; + for (int i = 0; i < result.length; i++) { + result[i] = ((AnnotationValue.OfShort) values.get(i)).shortValue(); + } + return result; + } + case AnnotationValue.OfChar _ -> { + List values = arrayValue.values(); + char[] result = new char[values.size()]; + for (int i = 0; i < result.length; i++) { + result[i] = ((AnnotationValue.OfChar) values.get(i)).charValue(); + } + return result; + } + case AnnotationValue.OfBoolean _ -> { + List values = arrayValue.values(); + boolean[] result = new boolean[values.size()]; + for (int i = 0; i < result.length; i++) { + result[i] = ((AnnotationValue.OfBoolean) values.get(i)).booleanValue(); + } + return result; + } + case AnnotationValue.OfFloat _ -> { + List values = arrayValue.values(); + float[] result = new float[values.size()]; + for (int i = 0; i < result.length; i++) { + result[i] = ((AnnotationValue.OfFloat) values.get(i)).floatValue(); + } + return result; + } default -> { Class arrayElementType = resolveArrayElementType(arrayValue.values(), classLoader); return stream diff --git a/spring-core/src/test/java24/org/springframework/core/type/classreading/ClassFileAnnotationDelegatePrimitiveArrayTests.java b/spring-core/src/test/java24/org/springframework/core/type/classreading/ClassFileAnnotationDelegatePrimitiveArrayTests.java new file mode 100644 index 000000000000..b1b0c9453863 --- /dev/null +++ b/spring-core/src/test/java24/org/springframework/core/type/classreading/ClassFileAnnotationDelegatePrimitiveArrayTests.java @@ -0,0 +1,95 @@ +/* + * Copyright 2002-present 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +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.annotation.MergedAnnotation; +import org.springframework.core.io.DefaultResourceLoader; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for primitive array attribute parsing by the {@code java.lang.classfile} + * based {@link ClassFileAnnotationDelegate}. Mirrors the ASM-based + * {@code MergedAnnotationMetadataVisitorTests} expectations. + * + * @author junhyeong9812 + */ +class ClassFileAnnotationDelegatePrimitiveArrayTests { + + @Test + void parsesNonEmptyPrimitiveArrayAttributes() throws Exception { + MergedAnnotation annotation = readAnnotation(WithArrays.class); + assertThat(annotation.getValue("byteValue")).contains(new byte[] { 1 }); + assertThat(annotation.getValue("shortValue")).contains(new short[] { 2 }); + assertThat(annotation.getValue("intValue")).contains(new int[] { 3 }); + assertThat(annotation.getValue("longValue")).contains(new long[] { 4 }); + assertThat(annotation.getValue("booleanValue")).contains(new boolean[] { true }); + assertThat(annotation.getValue("charValue")).contains(new char[] { 'c' }); + assertThat(annotation.getValue("doubleValue")).contains(new double[] { 5.0 }); + assertThat(annotation.getValue("floatValue")).contains(new float[] { 6.0f }); + } + + @Test + void parsesEmptyPrimitiveArrayAttributes() throws Exception { + MergedAnnotation annotation = readAnnotation(WithEmptyArrays.class); + assertThat(annotation.getValue("byteValue")).contains(new byte[] {}); + assertThat(annotation.getValue("floatValue")).contains(new float[] {}); + } + + private static MergedAnnotation readAnnotation(Class type) throws Exception { + ClassFileMetadataReaderFactory factory = new ClassFileMetadataReaderFactory(new DefaultResourceLoader()); + MetadataReader reader = factory.getMetadataReader(type.getName()); + return reader.getAnnotationMetadata().getAnnotations().get(ArrayTypesAnnotation.class); + } + + + @ArrayTypesAnnotation(byteValue = 1, shortValue = 2, intValue = 3, longValue = 4, + booleanValue = true, charValue = 'c', doubleValue = 5.0, floatValue = 6.0f) + static class WithArrays { + } + + @ArrayTypesAnnotation(byteValue = {}, shortValue = {}, intValue = {}, longValue = {}, + booleanValue = {}, charValue = {}, doubleValue = {}, floatValue = {}) + static class WithEmptyArrays { + } + + @Retention(RetentionPolicy.RUNTIME) + @interface ArrayTypesAnnotation { + + byte[] byteValue(); + + short[] shortValue(); + + int[] intValue(); + + long[] longValue(); + + boolean[] booleanValue(); + + char[] charValue(); + + double[] doubleValue(); + + float[] floatValue(); + } + +}