diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementAdapter.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementAdapter.java new file mode 100644 index 0000000000..f6456d879c --- /dev/null +++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementAdapter.java @@ -0,0 +1,130 @@ +/* + * Copyright 2002-2025 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.annotation; + +import java.io.Serializable; +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.util.Arrays; + +import org.jspecify.annotations.Nullable; + +/** + * Adapter for exposing a set of annotations as an {@link AnnotatedElement}, in + * particular as input for various methods in {@link AnnotatedElementUtils}. + * + * @author Juergen Hoeller + * @author Sam Brannen + * @since 7.0 + * @see #from(Annotation[]) + * @see AnnotatedElementUtils#isAnnotated(AnnotatedElement, Class) + * @see AnnotatedElementUtils#getMergedAnnotation(AnnotatedElement, Class) + */ +@SuppressWarnings("serial") +public final class AnnotatedElementAdapter implements AnnotatedElement, Serializable { + + private static final AnnotatedElementAdapter EMPTY = new AnnotatedElementAdapter(new Annotation[0]); + + + /** + * Create an {@code AnnotatedElementAdapter} from the supplied annotations. + *
The supplied annotations will be considered to be both present + * and directly present with regard to the results returned from + * methods such as {@link #getAnnotation(Class)}, + * {@link #getDeclaredAnnotation(Class)}, etc. + *
If the supplied annotations array is either {@code null} or empty, this
+ * factory method will return an {@linkplain #isEmpty() empty} adapter.
+ * @param annotations the annotations to expose via the {@link AnnotatedElement}
+ * API
+ * @return a new {@code AnnotatedElementAdapter}
+ */
+ public static AnnotatedElementAdapter from(Annotation @Nullable [] annotations) {
+ if (annotations == null || annotations.length == 0) {
+ return EMPTY;
+ }
+ return new AnnotatedElementAdapter(annotations);
+ }
+
+
+ private final Annotation[] annotations;
+
+
+ private AnnotatedElementAdapter(Annotation[] annotations) {
+ this.annotations = annotations;
+ }
+
+
+ @Override
+ public boolean isAnnotationPresent(Class extends Annotation> annotationClass) {
+ for (Annotation annotation : this.annotations) {
+ if (annotation.annotationType() == annotationClass) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public @Nullable A getAnnotation(Class annotationClass) {
+ for (Annotation annotation : this.annotations) {
+ if (annotation.annotationType() == annotationClass) {
+ return annotationClass.cast(annotation);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Annotation[] getAnnotations() {
+ return (isEmpty() ? this.annotations : this.annotations.clone());
+ }
+
+ @Override
+ public @Nullable A getDeclaredAnnotation(Class annotationClass) {
+ return getAnnotation(annotationClass);
+ }
+
+ @Override
+ public Annotation[] getDeclaredAnnotations() {
+ return getAnnotations();
+ }
+
+ /**
+ * Determine if this {@code AnnotatedElementAdapter} is empty.
+ * @return {@code true} if this adapter contains no annotations
+ */
+ public boolean isEmpty() {
+ return (this == EMPTY);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object other) {
+ return (this == other || (other instanceof AnnotatedElementAdapter that &&
+ Arrays.equals(this.annotations, that.annotations)));
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(this.annotations);
+ }
+
+ @Override
+ public String toString() {
+ return Arrays.toString(this.annotations);
+ }
+
+}
diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java
index 80e044a45a..b79a97b47d 100644
--- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java
+++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java
@@ -100,12 +100,12 @@ public abstract class AnnotatedElementUtils {
/**
* Build an adapted {@link AnnotatedElement} for the given annotations,
- * typically for use with other methods on {@link AnnotatedElementUtils}.
+ * typically for use with other methods in {@link AnnotatedElementUtils}.
* @param annotations the annotations to expose through the {@code AnnotatedElement}
* @since 4.3
*/
public static AnnotatedElement forAnnotations(Annotation... annotations) {
- return new AnnotatedElementForAnnotations(annotations);
+ return AnnotatedElementAdapter.from(annotations);
}
/**
@@ -837,39 +837,4 @@ public abstract class AnnotatedElementUtils {
return annotation.asAnnotationAttributes(Adapt.values(classValuesAsString, nestedAnnotationsAsMap));
}
-
- /**
- * Adapted {@link AnnotatedElement} that holds specific annotations.
- */
- private static class AnnotatedElementForAnnotations implements AnnotatedElement {
-
- private final Annotation[] annotations;
-
- AnnotatedElementForAnnotations(Annotation... annotations) {
- this.annotations = annotations;
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public Capable of representing arrays and generic collection types.
*
* @author Keith Donald
@@ -731,82 +732,6 @@ public class TypeDescriptor implements Serializable {
}
- /**
- * Adapter class for exposing a {@code TypeDescriptor}'s annotations as an
- * {@link AnnotatedElement}, in particular to {@link AnnotatedElementUtils}.
- * @see AnnotatedElementUtils#isAnnotated(AnnotatedElement, Class)
- * @see AnnotatedElementUtils#getMergedAnnotation(AnnotatedElement, Class)
- */
- private static final class AnnotatedElementAdapter implements AnnotatedElement, Serializable {
-
- private static final AnnotatedElementAdapter EMPTY = new AnnotatedElementAdapter(new Annotation[0]);
-
- private final Annotation[] annotations;
-
- private AnnotatedElementAdapter(Annotation[] annotations) {
- this.annotations = annotations;
- }
-
- private static AnnotatedElementAdapter from(Annotation @Nullable [] annotations) {
- if (annotations == null || annotations.length == 0) {
- return EMPTY;
- }
- return new AnnotatedElementAdapter(annotations);
- }
-
- @Override
- public boolean isAnnotationPresent(Class extends Annotation> annotationClass) {
- for (Annotation annotation : this.annotations) {
- if (annotation.annotationType() == annotationClass) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public