mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-17 16:39:29 +00:00
Merge branch '7.0.x'
This commit is contained in:
@@ -623,7 +623,7 @@ public interface MergedAnnotation<A extends Annotation> {
|
||||
* @param annotationType the annotation type
|
||||
* @param attributes the annotation attributes or {@code null} if just default
|
||||
* values should be used
|
||||
* @return a {@link MergedAnnotation} instance for the annotation and attributes
|
||||
* @return a {@link MergedAnnotation} instance for the annotation type and attributes
|
||||
*/
|
||||
static <A extends Annotation> MergedAnnotation<A> of(
|
||||
@Nullable ClassLoader classLoader, @Nullable Object source,
|
||||
|
||||
+10
-8
@@ -446,15 +446,17 @@ public interface MergedAnnotations extends Iterable<MergedAnnotation<Annotation>
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link MergedAnnotations} instance from the specified
|
||||
* collection of directly present annotations. This method allows a
|
||||
* {@code MergedAnnotations} instance to be created from annotations that
|
||||
* are not necessarily loaded using reflection. The provided annotations
|
||||
* must all be {@link MergedAnnotation#isDirectlyPresent() directly present}
|
||||
* and must have an {@link MergedAnnotation#getAggregateIndex() aggregate
|
||||
* index} of {@code 0}.
|
||||
* Create a new {@link MergedAnnotations} instance from the provided
|
||||
* collection of annotations.
|
||||
* <p>This method allows a {@code MergedAnnotations} instance to be created
|
||||
* from annotations that are not necessarily loaded using reflection.
|
||||
* <p>The provided annotations must all be
|
||||
* {@link MergedAnnotation#isDirectlyPresent() directly present} and must have
|
||||
* an {@link MergedAnnotation#getAggregateIndex() aggregate index} of {@code 0}.
|
||||
* In addition, the provided collection must retain the source declaration order
|
||||
* of the annotations — for example, a {@link java.util.List}.
|
||||
* <p>The resulting {@code MergedAnnotations} instance will contain both the
|
||||
* specified annotations and any meta-annotations that can be read using
|
||||
* provided annotations and any meta-annotations that can be read using
|
||||
* reflection.
|
||||
* @param annotations the annotations to include
|
||||
* @return a {@code MergedAnnotations} instance containing the annotations
|
||||
|
||||
+2
-1
@@ -22,7 +22,8 @@ import org.springframework.core.type.ClassMetadata;
|
||||
|
||||
/**
|
||||
* Simple facade for accessing class metadata,
|
||||
* as read by an ASM {@link org.springframework.asm.ClassReader}.
|
||||
* as read by an ASM {@link org.springframework.asm.ClassReader} or the
|
||||
* {@code java.lang.classfile.ClassFile} API on Java 24 and higher.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ import org.springframework.core.io.ResourceLoader;
|
||||
|
||||
/**
|
||||
* Internal delegate for instantiating {@link MetadataReaderFactory} implementations.
|
||||
* For JDK < 24, the {@link SimpleMetadataReaderFactory} is being used.
|
||||
* For JDK < 24, the {@link SimpleMetadataReaderFactory} is used.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 7.0
|
||||
|
||||
+3
-3
@@ -26,7 +26,6 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@@ -43,6 +42,7 @@ import org.springframework.util.ClassUtils;
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
* @since 7.0
|
||||
*/
|
||||
abstract class ClassFileAnnotationDelegate {
|
||||
@@ -50,11 +50,11 @@ abstract class ClassFileAnnotationDelegate {
|
||||
static MergedAnnotations createMergedAnnotations(
|
||||
String className, RuntimeVisibleAnnotationsAttribute annotationAttribute, @Nullable ClassLoader classLoader) {
|
||||
|
||||
Set<MergedAnnotation<?>> annotations = annotationAttribute.annotations()
|
||||
List<MergedAnnotation<?>> annotations = annotationAttribute.annotations()
|
||||
.stream()
|
||||
.map(ann -> createMergedAnnotation(className, ann, classLoader))
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
.collect(Collectors.toList());
|
||||
return MergedAnnotations.of(annotations);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ import org.springframework.core.io.ResourceLoader;
|
||||
|
||||
/**
|
||||
* Internal delegate for instantiating {@link MetadataReaderFactory} implementations.
|
||||
* For JDK >= 24, the {@link ClassFileMetadataReaderFactory} is being used.
|
||||
* For JDK >= 24, the {@link ClassFileMetadataReaderFactory} is used.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @since 7.0
|
||||
|
||||
+14
-6
@@ -261,7 +261,9 @@ public abstract class AbstractAnnotationMetadataTests {
|
||||
assertThat(get(WithDirectAnnotations.class).getAnnotations().stream())
|
||||
.filteredOn(MergedAnnotation::isDirectlyPresent)
|
||||
.extracting(a -> a.getType().getName())
|
||||
.containsExactlyInAnyOrder(DirectAnnotation1.class.getName(), DirectAnnotation2.class.getName());
|
||||
// We do not use containsExactlyInAnyOrder(), because annotations
|
||||
// must be returned in source declaration order.
|
||||
.containsExactly(DirectAnnotation1.class.getName(), DirectAnnotation2.class.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -290,8 +292,10 @@ public abstract class AbstractAnnotationMetadataTests {
|
||||
MultiValueMap<String, Object> attributes =
|
||||
get(WithMetaAnnotationAttributes.class).getAllAnnotationAttributes(AnnotationAttributes.class.getName());
|
||||
assertThat(attributes).containsOnlyKeys("name", "size");
|
||||
assertThat(attributes.get("name")).containsExactlyInAnyOrder("m1", "m2");
|
||||
assertThat(attributes.get("size")).containsExactlyInAnyOrder(1, 2);
|
||||
// We do not use containsExactlyInAnyOrder(), because annotations
|
||||
// must be returned in source declaration order.
|
||||
assertThat(attributes.get("name")).containsExactly("m1", "m2");
|
||||
assertThat(attributes.get("size")).containsExactly(1, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -335,15 +339,19 @@ public abstract class AbstractAnnotationMetadataTests {
|
||||
@Test
|
||||
void getAnnotationTypesReturnsDirectAnnotations() {
|
||||
AnnotationMetadata metadata = get(WithDirectAnnotations.class);
|
||||
assertThat(metadata.getAnnotationTypes()).containsExactlyInAnyOrder(
|
||||
DirectAnnotation1.class.getName(), DirectAnnotation2.class.getName());
|
||||
// We do not use containsExactlyInAnyOrder(), because annotations
|
||||
// must be returned in source declaration order.
|
||||
assertThat(metadata.getAnnotationTypes())
|
||||
.containsExactly(DirectAnnotation1.class.getName(), DirectAnnotation2.class.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getMetaAnnotationTypesReturnsMetaAnnotations() {
|
||||
AnnotationMetadata metadata = get(WithMetaAnnotations.class);
|
||||
// We do not use containsExactlyInAnyOrder(), because annotations
|
||||
// must be returned in source declaration order.
|
||||
assertThat(metadata.getMetaAnnotationTypes(MetaAnnotationRoot.class.getName()))
|
||||
.containsExactlyInAnyOrder(MetaAnnotation1.class.getName(), MetaAnnotation2.class.getName());
|
||||
.containsExactly(MetaAnnotation1.class.getName(), MetaAnnotation2.class.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+7
-3
@@ -224,7 +224,9 @@ public abstract class AbstractMethodMetadataTests {
|
||||
Stream<Class<?>> types = metadata.getAnnotations().stream()
|
||||
.filter(MergedAnnotation::isDirectlyPresent)
|
||||
.map(MergedAnnotation::getType);
|
||||
assertThat(types).containsExactlyInAnyOrder(Tag.class, DirectAnnotation.class);
|
||||
// We do not use containsExactlyInAnyOrder(), because annotations
|
||||
// must be returned in source declaration order.
|
||||
assertThat(types).containsExactly(Tag.class, DirectAnnotation.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -254,8 +256,10 @@ public abstract class AbstractMethodMetadataTests {
|
||||
MultiValueMap<String, Object> attributes = getTagged(WithMetaAnnotationAttributes.class)
|
||||
.getAllAnnotationAttributes(AnnotationAttributes.class.getName());
|
||||
assertThat(attributes).containsOnlyKeys("name", "size");
|
||||
assertThat(attributes.get("name")).containsExactlyInAnyOrder("m1", "m2");
|
||||
assertThat(attributes.get("size")).containsExactlyInAnyOrder(1, 2);
|
||||
// We do not use containsExactlyInAnyOrder(), because annotations
|
||||
// must be returned in source declaration order.
|
||||
assertThat(attributes.get("name")).containsExactly("m1", "m2");
|
||||
assertThat(attributes.get("size")).containsExactly(1, 2);
|
||||
}
|
||||
|
||||
@Test // gh-24375
|
||||
|
||||
+3
-1
@@ -405,7 +405,9 @@ class AnnotationMetadataTests {
|
||||
assertThat(metadata.hasAnnotation(SpecialAttr.class.getName())).isTrue();
|
||||
|
||||
assertThat(metadata.hasAnnotation(NamedComposedAnnotation.class.getName())).isTrue();
|
||||
assertThat(metadata.getAnnotationTypes()).containsExactlyInAnyOrder(
|
||||
// We do not use containsExactlyInAnyOrder(), because annotations
|
||||
// must be returned in source declaration order.
|
||||
assertThat(metadata.getAnnotationTypes()).containsExactly(
|
||||
Component.class.getName(), Scope.class.getName(),
|
||||
SpecialAttr.class.getName(), DirectAnnotation.class.getName(),
|
||||
MetaMetaAnnotation.class.getName(), EnumSubclasses.class.getName(),
|
||||
|
||||
+13
-5
@@ -57,7 +57,9 @@ class InheritedAnnotationsAnnotationMetadataTests {
|
||||
|
||||
@Test
|
||||
void getAnnotationTypes() {
|
||||
assertThat(standardMetadata.getAnnotationTypes()).containsExactlyInAnyOrder(
|
||||
// We do not use containsExactlyInAnyOrder(), because annotations
|
||||
// must be returned in source declaration order.
|
||||
assertThat(standardMetadata.getAnnotationTypes()).containsExactly(
|
||||
NamedAnnotation3.class.getName(),
|
||||
InheritedComposedAnnotation.class.getName());
|
||||
|
||||
@@ -81,11 +83,14 @@ class InheritedAnnotationsAnnotationMetadataTests {
|
||||
Set<String> metaAnnotationTypes;
|
||||
|
||||
metaAnnotationTypes = standardMetadata.getMetaAnnotationTypes(InheritedComposedAnnotation.class.getName());
|
||||
assertThat(metaAnnotationTypes).containsExactlyInAnyOrder(
|
||||
MetaAnnotation.class.getName(),
|
||||
// We do not use containsExactlyInAnyOrder(), because annotations
|
||||
// must be returned in source declaration order, with local annotations
|
||||
// before meta-annotations.
|
||||
assertThat(metaAnnotationTypes).containsExactly(
|
||||
NamedAnnotation1.class.getName(),
|
||||
NamedAnnotation2.class.getName(),
|
||||
NamedAnnotation3.class.getName());
|
||||
NamedAnnotation3.class.getName(),
|
||||
MetaAnnotation.class.getName());
|
||||
|
||||
metaAnnotationTypes = asmMetadata.getMetaAnnotationTypes(InheritedComposedAnnotation.class.getName());
|
||||
assertThat(metaAnnotationTypes).isEmpty();
|
||||
@@ -138,7 +143,10 @@ class InheritedAnnotationsAnnotationMetadataTests {
|
||||
|
||||
annotationAttributes = standardMetadata.getAllAnnotationAttributes(NamedAnnotation3.class.getName());
|
||||
assertThat(annotationAttributes).containsKey("name");
|
||||
assertThat(annotationAttributes.get("name")).containsExactlyInAnyOrder("name 3", "local");
|
||||
// We do not use containsExactlyInAnyOrder(), because annotations
|
||||
// must be returned in source declaration order, with local annotations
|
||||
// before meta-annotations.
|
||||
assertThat(annotationAttributes.get("name")).containsExactly("local", "name 3");
|
||||
|
||||
annotationAttributes = asmMetadata.getAllAnnotationAttributes(NamedAnnotation1.class.getName());
|
||||
assertThat(annotationAttributes).isNull();
|
||||
|
||||
Reference in New Issue
Block a user