Migrate and verify annotation utility methods
Migrate all possible `AnnotationUtils` and `AnnotatedElementUtils` method to the `MergedAnnotation` API, verify results against the old implementations. All migrated methods now call both the new API and the old version and ensure that the same results or exceptions are raised. A full build of both Spring Framework and Spring Boot has been executed to ensure, as much as possible, that the migration does not cause unexpected regressions. See gh-22562
This commit is contained in:
parent
b91ccf038f
commit
a14bfe9a21
|
|
@ -35,7 +35,7 @@ import org.springframework.util.ObjectUtils;
|
|||
* @param <S> the type of source supported by this extractor
|
||||
* @see Annotation
|
||||
* @see AliasFor
|
||||
* @see AnnotationUtils#synthesizeAnnotation(Annotation, Object)
|
||||
* @see AnnotationUtils#synthesizeAnnotation(Annotation, java.lang.reflect.AnnotatedElement)
|
||||
*/
|
||||
abstract class AbstractAliasAwareAnnotationAttributeExtractor<S> implements AnnotationAttributeExtractor<S> {
|
||||
|
||||
|
|
|
|||
|
|
@ -18,10 +18,16 @@ package org.springframework.core.annotation;
|
|||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.core.BridgeMethodResolver;
|
||||
import org.springframework.core.annotation.MergedAnnotation.MapValues;
|
||||
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
|
|
@ -111,8 +117,15 @@ public abstract class AnnotatedElementUtils {
|
|||
* @see #getMetaAnnotationTypes(AnnotatedElement, String)
|
||||
* @see #hasMetaAnnotationTypes
|
||||
*/
|
||||
public static Set<String> getMetaAnnotationTypes(AnnotatedElement element, Class<? extends Annotation> annotationType) {
|
||||
return InternalAnnotatedElementUtils.getMetaAnnotationTypes(element, annotationType);
|
||||
public static Set<String> getMetaAnnotationTypes(AnnotatedElement element,
|
||||
Class<? extends Annotation> annotationType) {
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotatedElementUtils.getMetaAnnotationTypes(element, annotationType)
|
||||
).withDescription(() -> element + " " + annotationType
|
||||
).to(() ->
|
||||
getMetaAnnotationTypes(element, element.getAnnotation(annotationType))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -129,8 +142,31 @@ public abstract class AnnotatedElementUtils {
|
|||
* @see #getMetaAnnotationTypes(AnnotatedElement, Class)
|
||||
* @see #hasMetaAnnotationTypes
|
||||
*/
|
||||
public static Set<String> getMetaAnnotationTypes(AnnotatedElement element, String annotationName) {
|
||||
return InternalAnnotatedElementUtils.getMetaAnnotationTypes(element, annotationName);
|
||||
public static Set<String> getMetaAnnotationTypes(AnnotatedElement element,
|
||||
String annotationName) {
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotatedElementUtils.getMetaAnnotationTypes(element, annotationName)
|
||||
).withDescription(() -> element + " " + annotationName
|
||||
).to(() -> {
|
||||
for (Annotation annotation : element.getAnnotations()) {
|
||||
if (annotation.annotationType().getName().equals(annotationName)) {
|
||||
return getMetaAnnotationTypes(element, annotation);
|
||||
}
|
||||
}
|
||||
return Collections.emptySet();
|
||||
});
|
||||
}
|
||||
|
||||
private static Set<String> getMetaAnnotationTypes(AnnotatedElement element,
|
||||
@Nullable Annotation annotation) {
|
||||
|
||||
if (annotation == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
return getAnnotations(annotation.annotationType()).stream()
|
||||
.map(MergedAnnotation::getType)
|
||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -145,8 +181,15 @@ public abstract class AnnotatedElementUtils {
|
|||
* @since 4.2.3
|
||||
* @see #getMetaAnnotationTypes
|
||||
*/
|
||||
public static boolean hasMetaAnnotationTypes(AnnotatedElement element, Class<? extends Annotation> annotationType) {
|
||||
return InternalAnnotatedElementUtils.hasMetaAnnotationTypes(element, annotationType);
|
||||
public static boolean hasMetaAnnotationTypes(AnnotatedElement element,
|
||||
Class<? extends Annotation> annotationType) {
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotatedElementUtils.hasMetaAnnotationTypes(element, annotationType)
|
||||
).to(() ->
|
||||
getAnnotations(element).stream(annotationType)
|
||||
.anyMatch(MergedAnnotation::isMetaPresent)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -161,8 +204,15 @@ public abstract class AnnotatedElementUtils {
|
|||
* @return {@code true} if a matching meta-annotation is present
|
||||
* @see #getMetaAnnotationTypes
|
||||
*/
|
||||
public static boolean hasMetaAnnotationTypes(AnnotatedElement element, String annotationName) {
|
||||
return InternalAnnotatedElementUtils.hasMetaAnnotationTypes(element, annotationName);
|
||||
public static boolean hasMetaAnnotationTypes(AnnotatedElement element,
|
||||
String annotationName) {
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotatedElementUtils.hasMetaAnnotationTypes(element, annotationName)
|
||||
).to(() ->
|
||||
getAnnotations(element).stream(annotationName)
|
||||
.anyMatch(MergedAnnotation::isMetaPresent)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -179,8 +229,14 @@ public abstract class AnnotatedElementUtils {
|
|||
* @since 4.2.3
|
||||
* @see #hasAnnotation(AnnotatedElement, Class)
|
||||
*/
|
||||
public static boolean isAnnotated(AnnotatedElement element, Class<? extends Annotation> annotationType) {
|
||||
return InternalAnnotatedElementUtils.isAnnotated(element, annotationType);
|
||||
public static boolean isAnnotated(AnnotatedElement element,
|
||||
Class<? extends Annotation> annotationType) {
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotatedElementUtils.isAnnotated(element, annotationType)
|
||||
).to(() ->
|
||||
getAnnotations(element).isPresent(annotationType)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -196,7 +252,11 @@ public abstract class AnnotatedElementUtils {
|
|||
* @return {@code true} if a matching annotation is present
|
||||
*/
|
||||
public static boolean isAnnotated(AnnotatedElement element, String annotationName) {
|
||||
return InternalAnnotatedElementUtils.isAnnotated(element, annotationName);
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotatedElementUtils.isAnnotated(element, annotationName))
|
||||
.to(() ->
|
||||
getAnnotations(element).isPresent(annotationName)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -219,8 +279,15 @@ public abstract class AnnotatedElementUtils {
|
|||
@Nullable
|
||||
public static AnnotationAttributes getMergedAnnotationAttributes(
|
||||
AnnotatedElement element, Class<? extends Annotation> annotationType) {
|
||||
return InternalAnnotatedElementUtils.getMergedAnnotationAttributes(element,
|
||||
annotationType);
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotatedElementUtils.getMergedAnnotationAttributes(element,
|
||||
annotationType))
|
||||
.toNullable(() -> {
|
||||
MergedAnnotation<?> mergedAnnotation = getAnnotations(element)
|
||||
.get(annotationType, null, MergedAnnotationSelectors.firstDirectlyDeclared());
|
||||
return getAnnotationAttributes(mergedAnnotation, false, false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -242,9 +309,10 @@ public abstract class AnnotatedElementUtils {
|
|||
* @see #getAllAnnotationAttributes(AnnotatedElement, String)
|
||||
*/
|
||||
@Nullable
|
||||
public static AnnotationAttributes getMergedAnnotationAttributes(AnnotatedElement element, String annotationName) {
|
||||
return InternalAnnotatedElementUtils.getMergedAnnotationAttributes(element,
|
||||
annotationName);
|
||||
public static AnnotationAttributes getMergedAnnotationAttributes(
|
||||
AnnotatedElement element, String annotationName) {
|
||||
|
||||
return getMergedAnnotationAttributes(element, annotationName, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -274,10 +342,18 @@ public abstract class AnnotatedElementUtils {
|
|||
* @see #getAllAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
|
||||
*/
|
||||
@Nullable
|
||||
public static AnnotationAttributes getMergedAnnotationAttributes(AnnotatedElement element,
|
||||
String annotationName, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
|
||||
return InternalAnnotatedElementUtils.getMergedAnnotationAttributes(element,
|
||||
annotationName, classValuesAsString, nestedAnnotationsAsMap);
|
||||
public static AnnotationAttributes getMergedAnnotationAttributes(
|
||||
AnnotatedElement element, String annotationName, boolean classValuesAsString,
|
||||
boolean nestedAnnotationsAsMap) {
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotatedElementUtils.getMergedAnnotationAttributes(element,
|
||||
annotationName, classValuesAsString, nestedAnnotationsAsMap)
|
||||
).toNullable(() -> {
|
||||
MergedAnnotation<?> mergedAnnotation = getAnnotations(element)
|
||||
.get(annotationName, null, MergedAnnotationSelectors.firstDirectlyDeclared());
|
||||
return getAnnotationAttributes(mergedAnnotation, classValuesAsString, nestedAnnotationsAsMap);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -299,8 +375,15 @@ public abstract class AnnotatedElementUtils {
|
|||
* @see AnnotationUtils#synthesizeAnnotation(Map, Class, AnnotatedElement)
|
||||
*/
|
||||
@Nullable
|
||||
public static <A extends Annotation> A getMergedAnnotation(AnnotatedElement element, Class<A> annotationType) {
|
||||
return InternalAnnotatedElementUtils.getMergedAnnotation(element, annotationType);
|
||||
public static <A extends Annotation> A getMergedAnnotation(AnnotatedElement element,
|
||||
Class<A> annotationType) {
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotatedElementUtils.getMergedAnnotation(element, annotationType)
|
||||
).toNullable(() ->
|
||||
getAnnotations(element)
|
||||
.get(annotationType, null, MergedAnnotationSelectors.firstDirectlyDeclared())
|
||||
.synthesize(MergedAnnotation::isPresent).orElse(null)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -323,9 +406,15 @@ public abstract class AnnotatedElementUtils {
|
|||
* @see #getAllAnnotationAttributes(AnnotatedElement, String)
|
||||
* @see #findAllMergedAnnotations(AnnotatedElement, Class)
|
||||
*/
|
||||
public static <A extends Annotation> Set<A> getAllMergedAnnotations(AnnotatedElement element, Class<A> annotationType) {
|
||||
return InternalAnnotatedElementUtils.getAllMergedAnnotations(element,
|
||||
annotationType);
|
||||
public static <A extends Annotation> Set<A> getAllMergedAnnotations(
|
||||
AnnotatedElement element, Class<A> annotationType) {
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotatedElementUtils.getAllMergedAnnotations(element, annotationType)
|
||||
).to(() ->
|
||||
getAnnotations(element).stream(annotationType)
|
||||
.collect(MergedAnnotationCollectors.toAnnotationSet())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -346,9 +435,17 @@ public abstract class AnnotatedElementUtils {
|
|||
* @since 5.1
|
||||
* @see #getAllMergedAnnotations(AnnotatedElement, Class)
|
||||
*/
|
||||
public static Set<Annotation> getAllMergedAnnotations(AnnotatedElement element, Set<Class<? extends Annotation>> annotationTypes) {
|
||||
return InternalAnnotatedElementUtils.getAllMergedAnnotations(element,
|
||||
annotationTypes);
|
||||
public static Set<Annotation> getAllMergedAnnotations(AnnotatedElement element,
|
||||
Set<Class<? extends Annotation>> annotationTypes) {
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotatedElementUtils.getAllMergedAnnotations(element,
|
||||
annotationTypes)
|
||||
).to(() ->
|
||||
getAnnotations(element).stream()
|
||||
.filter(MergedAnnotationPredicates.typeIn(annotationTypes))
|
||||
.collect(MergedAnnotationCollectors.toAnnotationSet())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -375,10 +472,10 @@ public abstract class AnnotatedElementUtils {
|
|||
* @see #getAllMergedAnnotations(AnnotatedElement, Class)
|
||||
* @see #getMergedRepeatableAnnotations(AnnotatedElement, Class, Class)
|
||||
*/
|
||||
public static <A extends Annotation> Set<A> getMergedRepeatableAnnotations(AnnotatedElement element,
|
||||
Class<A> annotationType) {
|
||||
return InternalAnnotatedElementUtils.getMergedRepeatableAnnotations(element,
|
||||
annotationType);
|
||||
public static <A extends Annotation> Set<A> getMergedRepeatableAnnotations(
|
||||
AnnotatedElement element, Class<A> annotationType) {
|
||||
|
||||
return getMergedRepeatableAnnotations(element, annotationType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -407,10 +504,18 @@ public abstract class AnnotatedElementUtils {
|
|||
* @see #getMergedAnnotation(AnnotatedElement, Class)
|
||||
* @see #getAllMergedAnnotations(AnnotatedElement, Class)
|
||||
*/
|
||||
public static <A extends Annotation> Set<A> getMergedRepeatableAnnotations(AnnotatedElement element,
|
||||
Class<A> annotationType, @Nullable Class<? extends Annotation> containerType) {
|
||||
return InternalAnnotatedElementUtils.getMergedRepeatableAnnotations(element,
|
||||
annotationType, containerType);
|
||||
public static <A extends Annotation> Set<A> getMergedRepeatableAnnotations(
|
||||
AnnotatedElement element, Class<A> annotationType,
|
||||
@Nullable Class<? extends Annotation> containerType) {
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotatedElementUtils.getMergedRepeatableAnnotations(element,
|
||||
annotationType, containerType)
|
||||
).to(() ->
|
||||
getRepeatableAnnotations(element, containerType, annotationType)
|
||||
.stream(annotationType)
|
||||
.collect(MergedAnnotationCollectors.toAnnotationSet())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -428,9 +533,10 @@ public abstract class AnnotatedElementUtils {
|
|||
* @see #getAllAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
|
||||
*/
|
||||
@Nullable
|
||||
public static MultiValueMap<String, Object> getAllAnnotationAttributes(AnnotatedElement element, String annotationName) {
|
||||
return InternalAnnotatedElementUtils.getAllAnnotationAttributes(element,
|
||||
annotationName);
|
||||
public static MultiValueMap<String, Object> getAllAnnotationAttributes(
|
||||
AnnotatedElement element, String annotationName) {
|
||||
|
||||
return getAllAnnotationAttributes(element, annotationName, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -452,10 +558,20 @@ public abstract class AnnotatedElementUtils {
|
|||
* attributes from all annotations found, or {@code null} if not found
|
||||
*/
|
||||
@Nullable
|
||||
public static MultiValueMap<String, Object> getAllAnnotationAttributes(AnnotatedElement element,
|
||||
String annotationName, final boolean classValuesAsString, final boolean nestedAnnotationsAsMap) {
|
||||
return InternalAnnotatedElementUtils.getAllAnnotationAttributes(element,
|
||||
annotationName, classValuesAsString, nestedAnnotationsAsMap);
|
||||
public static MultiValueMap<String, Object> getAllAnnotationAttributes(
|
||||
AnnotatedElement element, String annotationName,
|
||||
final boolean classValuesAsString, final boolean nestedAnnotationsAsMap) {
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotatedElementUtils.getAllAnnotationAttributes(element,
|
||||
annotationName, classValuesAsString, nestedAnnotationsAsMap)
|
||||
).toNullable(() ->{
|
||||
MapValues[] mapValues = MapValues.of(classValuesAsString, nestedAnnotationsAsMap);
|
||||
return getAnnotations(element).stream(annotationName)
|
||||
.filter(MergedAnnotationPredicates.unique(AnnotatedElementUtils::parentAndType))
|
||||
.map(MergedAnnotation::withNonMergedAttributes)
|
||||
.collect(MergedAnnotationCollectors.toMultiValueMap(AnnotatedElementUtils::nullIfEmpty, mapValues));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -472,8 +588,18 @@ public abstract class AnnotatedElementUtils {
|
|||
* @since 4.3
|
||||
* @see #isAnnotated(AnnotatedElement, Class)
|
||||
*/
|
||||
public static boolean hasAnnotation(AnnotatedElement element, Class<? extends Annotation> annotationType) {
|
||||
return InternalAnnotatedElementUtils.hasAnnotation(element, annotationType);
|
||||
public static boolean hasAnnotation(AnnotatedElement element,
|
||||
Class<? extends Annotation> annotationType) {
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotatedElementUtils.hasAnnotation(element, annotationType)
|
||||
).withSkippedEquivalentCheck(() ->
|
||||
InternalAnnotatedElementUtils.hasAnnotation(element, annotationType) &&
|
||||
InternalAnnotatedElementUtils.findMergedAnnotationAttributes(element,
|
||||
annotationType.getName(), false, false) == null
|
||||
).to(() ->
|
||||
findAnnotations(element).isPresent(annotationType)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -504,10 +630,18 @@ public abstract class AnnotatedElementUtils {
|
|||
* @see #getMergedAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
|
||||
*/
|
||||
@Nullable
|
||||
public static AnnotationAttributes findMergedAnnotationAttributes(AnnotatedElement element,
|
||||
Class<? extends Annotation> annotationType, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
|
||||
return InternalAnnotatedElementUtils.findMergedAnnotationAttributes(element,
|
||||
annotationType, classValuesAsString, nestedAnnotationsAsMap);
|
||||
public static AnnotationAttributes findMergedAnnotationAttributes(
|
||||
AnnotatedElement element, Class<? extends Annotation> annotationType,
|
||||
boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotatedElementUtils.findMergedAnnotationAttributes(element,
|
||||
annotationType, classValuesAsString, nestedAnnotationsAsMap)
|
||||
).toNullable(() -> {
|
||||
MergedAnnotation<?> mergedAnnotation = findAnnotations(element)
|
||||
.get(annotationType, null, MergedAnnotationSelectors.firstDirectlyDeclared());
|
||||
return getAnnotationAttributes(mergedAnnotation, classValuesAsString, nestedAnnotationsAsMap);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -538,10 +672,18 @@ public abstract class AnnotatedElementUtils {
|
|||
* @see #getMergedAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
|
||||
*/
|
||||
@Nullable
|
||||
public static AnnotationAttributes findMergedAnnotationAttributes(AnnotatedElement element,
|
||||
String annotationName, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
|
||||
return InternalAnnotatedElementUtils.findMergedAnnotationAttributes(element,
|
||||
annotationName, classValuesAsString, nestedAnnotationsAsMap);
|
||||
public static AnnotationAttributes findMergedAnnotationAttributes(
|
||||
AnnotatedElement element, String annotationName, boolean classValuesAsString,
|
||||
boolean nestedAnnotationsAsMap) {
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotatedElementUtils.findMergedAnnotationAttributes(element,
|
||||
annotationName, classValuesAsString, nestedAnnotationsAsMap)
|
||||
).toNullable(() -> {
|
||||
MergedAnnotation<?> mergedAnnotation = findAnnotations(element)
|
||||
.get(annotationName, null, MergedAnnotationSelectors.firstDirectlyDeclared());
|
||||
return getAnnotationAttributes(mergedAnnotation, classValuesAsString, nestedAnnotationsAsMap);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -563,9 +705,16 @@ public abstract class AnnotatedElementUtils {
|
|||
* @see #getMergedAnnotationAttributes(AnnotatedElement, Class)
|
||||
*/
|
||||
@Nullable
|
||||
public static <A extends Annotation> A findMergedAnnotation(AnnotatedElement element, Class<A> annotationType) {
|
||||
return InternalAnnotatedElementUtils.findMergedAnnotation(element,
|
||||
annotationType);
|
||||
public static <A extends Annotation> A findMergedAnnotation(AnnotatedElement element,
|
||||
Class<A> annotationType) {
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotatedElementUtils.findMergedAnnotation(element, annotationType)
|
||||
).toNullable(() ->
|
||||
findAnnotations(element)
|
||||
.get(annotationType, null, MergedAnnotationSelectors.firstDirectlyDeclared())
|
||||
.synthesize(MergedAnnotation::isPresent).orElse(null)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -587,9 +736,17 @@ public abstract class AnnotatedElementUtils {
|
|||
* @see #findMergedAnnotation(AnnotatedElement, Class)
|
||||
* @see #getAllMergedAnnotations(AnnotatedElement, Class)
|
||||
*/
|
||||
public static <A extends Annotation> Set<A> findAllMergedAnnotations(AnnotatedElement element, Class<A> annotationType) {
|
||||
return InternalAnnotatedElementUtils.findAllMergedAnnotations(element,
|
||||
annotationType);
|
||||
public static <A extends Annotation> Set<A> findAllMergedAnnotations(
|
||||
AnnotatedElement element, Class<A> annotationType) {
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotatedElementUtils.findAllMergedAnnotations(element, annotationType)
|
||||
).withSkippedOriginalExceptionCheck().to(() ->
|
||||
findAnnotations(element)
|
||||
.stream(annotationType)
|
||||
.sorted(highAggregateIndexesFirst())
|
||||
.collect(MergedAnnotationCollectors.toAnnotationSet())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -610,9 +767,17 @@ public abstract class AnnotatedElementUtils {
|
|||
* @since 5.1
|
||||
* @see #findAllMergedAnnotations(AnnotatedElement, Class)
|
||||
*/
|
||||
public static Set<Annotation> findAllMergedAnnotations(AnnotatedElement element, Set<Class<? extends Annotation>> annotationTypes) {
|
||||
return InternalAnnotatedElementUtils.findAllMergedAnnotations(element,
|
||||
annotationTypes);
|
||||
public static Set<Annotation> findAllMergedAnnotations(AnnotatedElement element,
|
||||
Set<Class<? extends Annotation>> annotationTypes) {
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotatedElementUtils.findAllMergedAnnotations(element, annotationTypes)
|
||||
).to(()->
|
||||
findAnnotations(element).stream()
|
||||
.filter(MergedAnnotationPredicates.typeIn(annotationTypes))
|
||||
.sorted(highAggregateIndexesFirst())
|
||||
.collect(MergedAnnotationCollectors.toAnnotationSet())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -639,10 +804,10 @@ public abstract class AnnotatedElementUtils {
|
|||
* @see #findAllMergedAnnotations(AnnotatedElement, Class)
|
||||
* @see #findMergedRepeatableAnnotations(AnnotatedElement, Class, Class)
|
||||
*/
|
||||
public static <A extends Annotation> Set<A> findMergedRepeatableAnnotations(AnnotatedElement element,
|
||||
Class<A> annotationType) {
|
||||
return InternalAnnotatedElementUtils.findMergedRepeatableAnnotations(element,
|
||||
annotationType);
|
||||
public static <A extends Annotation> Set<A> findMergedRepeatableAnnotations(
|
||||
AnnotatedElement element, Class<A> annotationType) {
|
||||
|
||||
return findMergedRepeatableAnnotations(element, annotationType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -671,10 +836,75 @@ public abstract class AnnotatedElementUtils {
|
|||
* @see #findMergedAnnotation(AnnotatedElement, Class)
|
||||
* @see #findAllMergedAnnotations(AnnotatedElement, Class)
|
||||
*/
|
||||
public static <A extends Annotation> Set<A> findMergedRepeatableAnnotations(AnnotatedElement element,
|
||||
Class<A> annotationType, @Nullable Class<? extends Annotation> containerType) {
|
||||
return InternalAnnotatedElementUtils.findMergedRepeatableAnnotations(element,
|
||||
annotationType, containerType);
|
||||
public static <A extends Annotation> Set<A> findMergedRepeatableAnnotations(
|
||||
AnnotatedElement element, Class<A> annotationType,
|
||||
@Nullable Class<? extends Annotation> containerType) {
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotatedElementUtils.findMergedRepeatableAnnotations(element,
|
||||
annotationType, containerType)
|
||||
).to(() ->
|
||||
findRepeatableAnnotations(element, containerType, annotationType)
|
||||
.stream(annotationType)
|
||||
.sorted(highAggregateIndexesFirst())
|
||||
.collect(MergedAnnotationCollectors.toAnnotationSet())
|
||||
);
|
||||
}
|
||||
|
||||
private static MergedAnnotations getAnnotations(AnnotatedElement element) {
|
||||
return MergedAnnotations.from(element, SearchStrategy.INHERITED_ANNOTATIONS,
|
||||
RepeatableContainers.none(), AnnotationUtils.JAVA_LANG_ANNOTATION_FILTER);
|
||||
}
|
||||
|
||||
private static MergedAnnotations getRepeatableAnnotations(AnnotatedElement element,
|
||||
@Nullable Class<? extends Annotation> containerType,
|
||||
Class<? extends Annotation> annotationType) {
|
||||
|
||||
RepeatableContainers repeatableContainers = RepeatableContainers.of(annotationType, containerType);
|
||||
return MergedAnnotations.from(element, SearchStrategy.INHERITED_ANNOTATIONS,
|
||||
repeatableContainers, AnnotationUtils.JAVA_LANG_ANNOTATION_FILTER);
|
||||
}
|
||||
|
||||
private static MergedAnnotations findAnnotations(AnnotatedElement element) {
|
||||
return MergedAnnotations.from(element, SearchStrategy.EXHAUSTIVE,
|
||||
RepeatableContainers.none(), AnnotationUtils.JAVA_LANG_ANNOTATION_FILTER);
|
||||
}
|
||||
|
||||
private static MergedAnnotations findRepeatableAnnotations(AnnotatedElement element,
|
||||
@Nullable Class<? extends Annotation> containerType,
|
||||
Class<? extends Annotation> annotationType) {
|
||||
|
||||
RepeatableContainers repeatableContainers = RepeatableContainers.of(annotationType, containerType);
|
||||
return MergedAnnotations.from(element, SearchStrategy.EXHAUSTIVE,
|
||||
repeatableContainers, AnnotationUtils.JAVA_LANG_ANNOTATION_FILTER);
|
||||
}
|
||||
|
||||
private static Object parentAndType(MergedAnnotation<Annotation> annotation) {
|
||||
if (annotation.getParent() == null) {
|
||||
return annotation.getType();
|
||||
}
|
||||
return annotation.getParent().getType() + ":" + annotation.getParent().getType();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static MultiValueMap<String, Object> nullIfEmpty(
|
||||
MultiValueMap<String, Object> map) {
|
||||
return map.isEmpty() ? null : map;
|
||||
}
|
||||
|
||||
private static <A extends Annotation> Comparator<MergedAnnotation<A>> highAggregateIndexesFirst() {
|
||||
return Comparator.<MergedAnnotation<A>>comparingInt(MergedAnnotation::getAggregateIndex).reversed();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static AnnotationAttributes getAnnotationAttributes(
|
||||
MergedAnnotation<?> annotation, boolean classValuesAsString,
|
||||
boolean nestedAnnotationsAsMap) {
|
||||
if (!annotation.isPresent()) {
|
||||
return null;
|
||||
}
|
||||
return annotation.asMap((mergedAnnotation) -> new AnnotationAttributes(),
|
||||
MapValues.of(classValuesAsString, nestedAnnotationsAsMap));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,6 +113,22 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
|
|||
this.displayName = annotationType.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a possibly already validated new, empty
|
||||
* {@link AnnotationAttributes} instance for the specified
|
||||
* {@code annotationType}.
|
||||
* @param annotationType the type of annotation represented by this
|
||||
* {@code AnnotationAttributes} instance; never {@code null}
|
||||
* @param validated if the attributes are considered already validated
|
||||
* @since 5.2
|
||||
*/
|
||||
AnnotationAttributes(Class<? extends Annotation> annotationType, boolean validated) {
|
||||
Assert.notNull(annotationType, "'annotationType' must not be null");
|
||||
this.annotationType = annotationType;
|
||||
this.displayName = annotationType.getName();
|
||||
this.validated = validated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new, empty {@link AnnotationAttributes} instance for the
|
||||
* specified {@code annotationType}.
|
||||
|
|
|
|||
|
|
@ -18,14 +18,28 @@ package org.springframework.core.annotation;
|
|||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.core.BridgeMethodResolver;
|
||||
import org.springframework.core.annotation.AnnotationTypeMapping.MirrorSets.MirrorSet;
|
||||
import org.springframework.core.annotation.InternalAnnotationUtils.DefaultValueHolder;
|
||||
import org.springframework.core.annotation.MergedAnnotation.MapValues;
|
||||
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ConcurrentReferenceHashMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* General utility methods for working with annotations, handling meta-annotations,
|
||||
|
|
@ -95,9 +109,16 @@ public abstract class AnnotationUtils {
|
|||
/**
|
||||
* The attribute name for annotations with a single element.
|
||||
*/
|
||||
public static final String VALUE = "value";
|
||||
public static final String VALUE = MergedAnnotation.VALUE;
|
||||
|
||||
|
||||
static final AnnotationFilter JAVA_LANG_ANNOTATION_FILTER =
|
||||
AnnotationFilter.packages("java.lang.annotation");
|
||||
|
||||
|
||||
private static Map<Class<? extends Annotation>, Map<String, DefaultValueHolder>> defaultValuesCache =
|
||||
new ConcurrentReferenceHashMap<>();
|
||||
|
||||
/**
|
||||
* Determine whether the given class is a candidate for carrying one of the specified
|
||||
* annotations (at type, method or field level).
|
||||
|
|
@ -160,8 +181,16 @@ public abstract class AnnotationUtils {
|
|||
* @since 4.0
|
||||
*/
|
||||
@Nullable
|
||||
public static <A extends Annotation> A getAnnotation(Annotation annotation, Class<A> annotationType) {
|
||||
return InternalAnnotationUtils.getAnnotation(annotation, annotationType);
|
||||
public static <A extends Annotation> A getAnnotation(Annotation annotation,
|
||||
Class<A> annotationType) {
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotationUtils.getAnnotation(annotation, annotationType)
|
||||
).toNullable(() ->
|
||||
MergedAnnotations.from(annotation)
|
||||
.get(annotationType).withNonMergedAttributes()
|
||||
.synthesize(AnnotationUtils::isSingleLevelPresent).orElse(null)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -177,8 +206,17 @@ public abstract class AnnotationUtils {
|
|||
* @since 3.1
|
||||
*/
|
||||
@Nullable
|
||||
public static <A extends Annotation> A getAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType) {
|
||||
return InternalAnnotationUtils.getAnnotation(annotatedElement, annotationType);
|
||||
public static <A extends Annotation> A getAnnotation(
|
||||
AnnotatedElement annotatedElement, Class<A> annotationType) {
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotationUtils.getAnnotation(annotatedElement, annotationType)
|
||||
).toNullable(() ->
|
||||
MergedAnnotations.from(annotatedElement, SearchStrategy.INHERITED_ANNOTATIONS,
|
||||
RepeatableContainers.none(), AnnotationFilter.PLAIN)
|
||||
.get(annotationType).withNonMergedAttributes()
|
||||
.synthesize(AnnotationUtils::isSingleLevelPresent).orElse(null)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -196,8 +234,17 @@ public abstract class AnnotationUtils {
|
|||
* @see #getAnnotation(AnnotatedElement, Class)
|
||||
*/
|
||||
@Nullable
|
||||
public static <A extends Annotation> A getAnnotation(Method method, Class<A> annotationType) {
|
||||
return InternalAnnotationUtils.getAnnotation(method, annotationType);
|
||||
public static <A extends Annotation> A getAnnotation(Method method,
|
||||
Class<A> annotationType) {
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotationUtils.getAnnotation(method, annotationType)
|
||||
).toNullable(() ->
|
||||
MergedAnnotations.from(method, SearchStrategy.INHERITED_ANNOTATIONS,
|
||||
RepeatableContainers.none(), AnnotationFilter.PLAIN)
|
||||
.get(annotationType).withNonMergedAttributes()
|
||||
.synthesize(AnnotationUtils::isSingleLevelPresent).orElse(null)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -213,7 +260,15 @@ public abstract class AnnotationUtils {
|
|||
*/
|
||||
@Nullable
|
||||
public static Annotation[] getAnnotations(AnnotatedElement annotatedElement) {
|
||||
return InternalAnnotationUtils.getAnnotations(annotatedElement);
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotationUtils.getAnnotations(annotatedElement)
|
||||
).toNullable(() ->
|
||||
MergedAnnotations.from(annotatedElement, SearchStrategy.INHERITED_ANNOTATIONS,
|
||||
RepeatableContainers.none(), AnnotationFilter.NONE).stream()
|
||||
.filter(MergedAnnotation::isDirectlyPresent)
|
||||
.map(MergedAnnotation::withNonMergedAttributes)
|
||||
.collect(MergedAnnotationCollectors.toAnnotationArray())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -230,7 +285,15 @@ public abstract class AnnotationUtils {
|
|||
*/
|
||||
@Nullable
|
||||
public static Annotation[] getAnnotations(Method method) {
|
||||
return InternalAnnotationUtils.getAnnotations(method);
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotationUtils.getAnnotations(method)
|
||||
).toNullable(()->
|
||||
MergedAnnotations.from(method, SearchStrategy.INHERITED_ANNOTATIONS,
|
||||
RepeatableContainers.none(), AnnotationFilter.NONE).stream()
|
||||
.filter(MergedAnnotation::isDirectlyPresent)
|
||||
.map(MergedAnnotation::withNonMergedAttributes)
|
||||
.collect(MergedAnnotationCollectors.toAnnotationArray())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -260,10 +323,10 @@ public abstract class AnnotationUtils {
|
|||
* @see java.lang.annotation.Repeatable
|
||||
* @see java.lang.reflect.AnnotatedElement#getAnnotationsByType
|
||||
*/
|
||||
public static <A extends Annotation> Set<A> getRepeatableAnnotations(AnnotatedElement annotatedElement,
|
||||
Class<A> annotationType) {
|
||||
return InternalAnnotationUtils.getRepeatableAnnotations(annotatedElement,
|
||||
annotationType);
|
||||
public static <A extends Annotation> Set<A> getRepeatableAnnotations(
|
||||
AnnotatedElement annotatedElement, Class<A> annotationType) {
|
||||
|
||||
return getRepeatableAnnotations(annotatedElement, annotationType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -296,10 +359,25 @@ public abstract class AnnotationUtils {
|
|||
* @see java.lang.annotation.Repeatable
|
||||
* @see java.lang.reflect.AnnotatedElement#getAnnotationsByType
|
||||
*/
|
||||
public static <A extends Annotation> Set<A> getRepeatableAnnotations(AnnotatedElement annotatedElement,
|
||||
Class<A> annotationType, @Nullable Class<? extends Annotation> containerAnnotationType) {
|
||||
return InternalAnnotationUtils.getRepeatableAnnotations(annotatedElement,
|
||||
annotationType, containerAnnotationType);
|
||||
public static <A extends Annotation> Set<A> getRepeatableAnnotations(
|
||||
AnnotatedElement annotatedElement, Class<A> annotationType,
|
||||
@Nullable Class<? extends Annotation> containerAnnotationType) {
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotationUtils.getRepeatableAnnotations(annotatedElement,
|
||||
annotationType, containerAnnotationType)
|
||||
).to(() -> {
|
||||
RepeatableContainers repeatableContainers = containerAnnotationType != null ?
|
||||
RepeatableContainers.of(annotationType, containerAnnotationType) :
|
||||
RepeatableContainers.standardRepeatables();
|
||||
AnnotationFilter annotationFilter = AnnotationFilter.mostAppropriateFor(annotationType);
|
||||
return MergedAnnotations.from(annotatedElement, SearchStrategy.SUPER_CLASS,
|
||||
repeatableContainers, annotationFilter)
|
||||
.stream(annotationType)
|
||||
.filter(MergedAnnotationPredicates.firstRunOf(MergedAnnotation::getAggregateIndex))
|
||||
.map(MergedAnnotation::withNonMergedAttributes)
|
||||
.collect(MergedAnnotationCollectors.toAnnotationSet());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -330,10 +408,10 @@ public abstract class AnnotationUtils {
|
|||
* @see java.lang.annotation.Repeatable
|
||||
* @see java.lang.reflect.AnnotatedElement#getDeclaredAnnotationsByType
|
||||
*/
|
||||
public static <A extends Annotation> Set<A> getDeclaredRepeatableAnnotations(AnnotatedElement annotatedElement,
|
||||
Class<A> annotationType) {
|
||||
return InternalAnnotationUtils.getDeclaredRepeatableAnnotations(annotatedElement,
|
||||
annotationType);
|
||||
public static <A extends Annotation> Set<A> getDeclaredRepeatableAnnotations(
|
||||
AnnotatedElement annotatedElement, Class<A> annotationType) {
|
||||
|
||||
return getDeclaredRepeatableAnnotations(annotatedElement, annotationType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -366,10 +444,25 @@ public abstract class AnnotationUtils {
|
|||
* @see java.lang.annotation.Repeatable
|
||||
* @see java.lang.reflect.AnnotatedElement#getDeclaredAnnotationsByType
|
||||
*/
|
||||
public static <A extends Annotation> Set<A> getDeclaredRepeatableAnnotations(AnnotatedElement annotatedElement,
|
||||
Class<A> annotationType, @Nullable Class<? extends Annotation> containerAnnotationType) {
|
||||
return InternalAnnotationUtils.getDeclaredRepeatableAnnotations(annotatedElement,
|
||||
annotationType, containerAnnotationType);
|
||||
public static <A extends Annotation> Set<A> getDeclaredRepeatableAnnotations(
|
||||
AnnotatedElement annotatedElement, Class<A> annotationType,
|
||||
@Nullable Class<? extends Annotation> containerAnnotationType) {
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotationUtils.getDeclaredRepeatableAnnotations(annotatedElement,
|
||||
annotationType, containerAnnotationType)
|
||||
).to(() -> {
|
||||
RepeatableContainers repeatableContainers = containerAnnotationType != null ?
|
||||
RepeatableContainers.of(annotationType, containerAnnotationType) :
|
||||
RepeatableContainers.standardRepeatables();
|
||||
AnnotationFilter annotationFilter = AnnotationFilter.mostAppropriateFor(
|
||||
annotationType, containerAnnotationType);
|
||||
return MergedAnnotations.from(annotatedElement, SearchStrategy.DIRECT,
|
||||
repeatableContainers, annotationFilter).stream(annotationType)
|
||||
.map(MergedAnnotation::withNonMergedAttributes)
|
||||
.collect(MergedAnnotationCollectors.toAnnotationSet());
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -389,8 +482,18 @@ public abstract class AnnotationUtils {
|
|||
* @since 4.2
|
||||
*/
|
||||
@Nullable
|
||||
public static <A extends Annotation> A findAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType) {
|
||||
return InternalAnnotationUtils.findAnnotation(annotatedElement, annotationType);
|
||||
public static <A extends Annotation> A findAnnotation(
|
||||
AnnotatedElement annotatedElement, Class<A> annotationType) {
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotationUtils.findAnnotation(annotatedElement, annotationType)
|
||||
).toNullable(() ->{
|
||||
AnnotationFilter annotationFilter = AnnotationFilter.mostAppropriateFor(annotationType);
|
||||
return MergedAnnotations.from(annotatedElement, SearchStrategy.DIRECT,
|
||||
RepeatableContainers.none(), annotationFilter)
|
||||
.get(annotationType).withNonMergedAttributes()
|
||||
.synthesize(MergedAnnotation::isPresent).orElse(null);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -409,8 +512,19 @@ public abstract class AnnotationUtils {
|
|||
* @see #getAnnotation(Method, Class)
|
||||
*/
|
||||
@Nullable
|
||||
public static <A extends Annotation> A findAnnotation(Method method, @Nullable Class<A> annotationType) {
|
||||
return InternalAnnotationUtils.findAnnotation(method, annotationType);
|
||||
public static <A extends Annotation> A findAnnotation(Method method,
|
||||
@Nullable Class<A> annotationType) {
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotationUtils.findAnnotation(method, annotationType)
|
||||
).toNullable(() -> {
|
||||
AnnotationFilter annotationFilter = AnnotationFilter.mostAppropriateFor(annotationType);
|
||||
return MergedAnnotations.from(method, SearchStrategy.EXHAUSTIVE,
|
||||
RepeatableContainers.none(), annotationFilter)
|
||||
.get(annotationType).withNonMergedAttributes()
|
||||
.synthesize(MergedAnnotation::isPresent).orElse(null);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -436,8 +550,19 @@ public abstract class AnnotationUtils {
|
|||
* @return the first matching annotation, or {@code null} if not found
|
||||
*/
|
||||
@Nullable
|
||||
public static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType) {
|
||||
return InternalAnnotationUtils.findAnnotation(clazz, annotationType);
|
||||
public static <A extends Annotation> A findAnnotation(Class<?> clazz,
|
||||
Class<A> annotationType) {
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotationUtils.findAnnotation(clazz, annotationType)
|
||||
).toNullable(() -> {
|
||||
AnnotationFilter annotationFilter = AnnotationFilter.mostAppropriateFor(annotationType);
|
||||
return MergedAnnotations.from(clazz, SearchStrategy.EXHAUSTIVE,
|
||||
RepeatableContainers.none(), annotationFilter)
|
||||
.get(annotationType).withNonMergedAttributes()
|
||||
.synthesize(MergedAnnotation::isPresent).orElse(null);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -463,9 +588,20 @@ public abstract class AnnotationUtils {
|
|||
* @see #isAnnotationDeclaredLocally(Class, Class)
|
||||
*/
|
||||
@Nullable
|
||||
public static Class<?> findAnnotationDeclaringClass(Class<? extends Annotation> annotationType, @Nullable Class<?> clazz) {
|
||||
return InternalAnnotationUtils.findAnnotationDeclaringClass(annotationType,
|
||||
clazz);
|
||||
public static Class<?> findAnnotationDeclaringClass(
|
||||
Class<? extends Annotation> annotationType, @Nullable Class<?> clazz) {
|
||||
|
||||
return MigrateMethod.<Class<?>> from(() ->
|
||||
InternalAnnotationUtils.findAnnotationDeclaringClass(annotationType,
|
||||
clazz)
|
||||
).toNullable(() -> {
|
||||
AnnotationFilter annotationFilter = AnnotationFilter.mostAppropriateFor(annotationType);
|
||||
return (Class<?>) MergedAnnotations.from(clazz, SearchStrategy.SUPER_CLASS,
|
||||
RepeatableContainers.none(), annotationFilter)
|
||||
.get(annotationType, MergedAnnotation::isDirectlyPresent)
|
||||
.getSource();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -495,8 +631,20 @@ public abstract class AnnotationUtils {
|
|||
@Nullable
|
||||
public static Class<?> findAnnotationDeclaringClassForTypes(
|
||||
List<Class<? extends Annotation>> annotationTypes, @Nullable Class<?> clazz) {
|
||||
return InternalAnnotationUtils.findAnnotationDeclaringClassForTypes(
|
||||
annotationTypes, clazz);
|
||||
|
||||
return MigrateMethod.<Class<?>> from(() ->
|
||||
InternalAnnotationUtils.findAnnotationDeclaringClassForTypes(
|
||||
annotationTypes, clazz)
|
||||
).toNullable(() -> {
|
||||
AnnotationFilter annotationFilter = AnnotationFilter.mostAppropriateFor(annotationTypes);
|
||||
return (Class<?>) MergedAnnotations.from(clazz, SearchStrategy.SUPER_CLASS,
|
||||
RepeatableContainers.none(), annotationFilter)
|
||||
.stream()
|
||||
.filter(MergedAnnotationPredicates.typeIn(annotationTypes).and(MergedAnnotation::isDirectlyPresent))
|
||||
.map(MergedAnnotation::getSource)
|
||||
.findFirst().orElse(null);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -517,8 +665,14 @@ public abstract class AnnotationUtils {
|
|||
* @see java.lang.Class#getDeclaredAnnotation(Class)
|
||||
* @see #isAnnotationInherited(Class, Class)
|
||||
*/
|
||||
public static boolean isAnnotationDeclaredLocally(Class<? extends Annotation> annotationType, Class<?> clazz) {
|
||||
return InternalAnnotationUtils.isAnnotationDeclaredLocally(annotationType, clazz);
|
||||
public static boolean isAnnotationDeclaredLocally(
|
||||
Class<? extends Annotation> annotationType, Class<?> clazz) {
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotationUtils.isAnnotationDeclaredLocally(annotationType, clazz)
|
||||
).withSkippedOriginalExceptionCheck().to(() ->
|
||||
MergedAnnotations.from(clazz).get(annotationType).isDirectlyPresent()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -540,8 +694,18 @@ public abstract class AnnotationUtils {
|
|||
* @see Class#isAnnotationPresent(Class)
|
||||
* @see #isAnnotationDeclaredLocally(Class, Class)
|
||||
*/
|
||||
public static boolean isAnnotationInherited(Class<? extends Annotation> annotationType, Class<?> clazz) {
|
||||
return InternalAnnotationUtils.isAnnotationInherited(annotationType, clazz);
|
||||
public static boolean isAnnotationInherited(
|
||||
Class<? extends Annotation> annotationType, Class<?> clazz) {
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotationUtils.isAnnotationInherited(annotationType, clazz)
|
||||
).to(() ->
|
||||
MergedAnnotations.from(clazz, SearchStrategy.INHERITED_ANNOTATIONS)
|
||||
.stream(annotationType)
|
||||
.filter(MergedAnnotation::isDirectlyPresent)
|
||||
.findFirst().orElseGet(MergedAnnotation::missing)
|
||||
.getAggregateIndex() > 0
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -552,10 +716,17 @@ public abstract class AnnotationUtils {
|
|||
* @return {@code true} if such an annotation is meta-present
|
||||
* @since 4.2.1
|
||||
*/
|
||||
public static boolean isAnnotationMetaPresent(Class<? extends Annotation> annotationType,
|
||||
public static boolean isAnnotationMetaPresent(
|
||||
Class<? extends Annotation> annotationType,
|
||||
@Nullable Class<? extends Annotation> metaAnnotationType) {
|
||||
return InternalAnnotationUtils.isAnnotationMetaPresent(annotationType,
|
||||
metaAnnotationType);
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotationUtils.isAnnotationMetaPresent(annotationType,
|
||||
metaAnnotationType)
|
||||
).to(() ->
|
||||
MergedAnnotations.from(annotationType, SearchStrategy.EXHAUSTIVE)
|
||||
.isPresent(annotationType)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -565,7 +736,11 @@ public abstract class AnnotationUtils {
|
|||
* @return {@code true} if the annotation is in the {@code java.lang.annotation} package
|
||||
*/
|
||||
public static boolean isInJavaLangAnnotationPackage(@Nullable Annotation annotation) {
|
||||
return InternalAnnotationUtils.isInJavaLangAnnotationPackage(annotation);
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotationUtils.isInJavaLangAnnotationPackage(annotation)
|
||||
).to(() ->
|
||||
JAVA_LANG_ANNOTATION_FILTER.matches(annotation)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -576,7 +751,11 @@ public abstract class AnnotationUtils {
|
|||
* @since 4.2
|
||||
*/
|
||||
public static boolean isInJavaLangAnnotationPackage(@Nullable String annotationType) {
|
||||
return InternalAnnotationUtils.isInJavaLangAnnotationPackage(annotationType);
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotationUtils.isInJavaLangAnnotationPackage(annotationType)
|
||||
).to(() ->
|
||||
JAVA_LANG_ANNOTATION_FILTER.matches(annotationType)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -592,7 +771,12 @@ public abstract class AnnotationUtils {
|
|||
* @see #getAnnotationAttributes(Annotation)
|
||||
*/
|
||||
public static void validateAnnotation(Annotation annotation) {
|
||||
InternalAnnotationUtils.validateAnnotation(annotation);
|
||||
MigrateMethod.fromCall(() ->
|
||||
InternalAnnotationUtils.validateAnnotation(annotation)
|
||||
).to(() ->
|
||||
AttributeMethods.forAnnotationType(annotation.annotationType())
|
||||
.validate(annotation)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -611,7 +795,7 @@ public abstract class AnnotationUtils {
|
|||
* @see #getAnnotationAttributes(AnnotatedElement, Annotation, boolean, boolean)
|
||||
*/
|
||||
public static Map<String, Object> getAnnotationAttributes(Annotation annotation) {
|
||||
return InternalAnnotationUtils.getAnnotationAttributes(annotation);
|
||||
return getAnnotationAttributes(null, annotation);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -628,9 +812,10 @@ public abstract class AnnotationUtils {
|
|||
* corresponding attribute values as values (never {@code null})
|
||||
* @see #getAnnotationAttributes(Annotation, boolean, boolean)
|
||||
*/
|
||||
public static Map<String, Object> getAnnotationAttributes(Annotation annotation, boolean classValuesAsString) {
|
||||
return InternalAnnotationUtils.getAnnotationAttributes(annotation,
|
||||
classValuesAsString);
|
||||
public static Map<String, Object> getAnnotationAttributes(Annotation annotation,
|
||||
boolean classValuesAsString) {
|
||||
|
||||
return getAnnotationAttributes(annotation, classValuesAsString, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -649,10 +834,11 @@ public abstract class AnnotationUtils {
|
|||
* and corresponding attribute values as values (never {@code null})
|
||||
* @since 3.1.1
|
||||
*/
|
||||
public static AnnotationAttributes getAnnotationAttributes(Annotation annotation, boolean classValuesAsString,
|
||||
boolean nestedAnnotationsAsMap) {
|
||||
return InternalAnnotationUtils.getAnnotationAttributes(annotation,
|
||||
classValuesAsString, nestedAnnotationsAsMap);
|
||||
public static AnnotationAttributes getAnnotationAttributes(Annotation annotation,
|
||||
boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
|
||||
|
||||
return getAnnotationAttributes(null, annotation, classValuesAsString,
|
||||
nestedAnnotationsAsMap);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -668,9 +854,10 @@ public abstract class AnnotationUtils {
|
|||
* @since 4.2
|
||||
* @see #getAnnotationAttributes(AnnotatedElement, Annotation, boolean, boolean)
|
||||
*/
|
||||
public static AnnotationAttributes getAnnotationAttributes(@Nullable AnnotatedElement annotatedElement, Annotation annotation) {
|
||||
return InternalAnnotationUtils.getAnnotationAttributes(annotatedElement,
|
||||
annotation);
|
||||
public static AnnotationAttributes getAnnotationAttributes(
|
||||
@Nullable AnnotatedElement annotatedElement, Annotation annotation) {
|
||||
|
||||
return getAnnotationAttributes(annotatedElement, annotation, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -691,10 +878,31 @@ public abstract class AnnotationUtils {
|
|||
* and corresponding attribute values as values (never {@code null})
|
||||
* @since 4.2
|
||||
*/
|
||||
public static AnnotationAttributes getAnnotationAttributes(@Nullable AnnotatedElement annotatedElement,
|
||||
Annotation annotation, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
|
||||
return InternalAnnotationUtils.getAnnotationAttributes(annotatedElement,
|
||||
annotation, classValuesAsString, nestedAnnotationsAsMap);
|
||||
public static AnnotationAttributes getAnnotationAttributes(
|
||||
@Nullable AnnotatedElement annotatedElement, Annotation annotation,
|
||||
boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotationUtils.getAnnotationAttributes(annotatedElement,
|
||||
annotation, classValuesAsString, nestedAnnotationsAsMap)
|
||||
).to(() -> {
|
||||
ClassLoader classLoader = annotation.annotationType().getClassLoader();
|
||||
MapValues[] mapValues = MapValues.of(classValuesAsString, nestedAnnotationsAsMap);
|
||||
return MergedAnnotation.from(annotatedElement, annotation)
|
||||
.withNonMergedAttributes()
|
||||
.asMap(getAnnotationAttributesFactory(classLoader), mapValues);
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Function<MergedAnnotation<?>, AnnotationAttributes> getAnnotationAttributesFactory(
|
||||
ClassLoader classLoader) {
|
||||
|
||||
return annotation -> {
|
||||
Class<Annotation> type = (Class<Annotation>) ClassUtils.resolveClassName(
|
||||
annotation.getType(), classLoader);
|
||||
return new AnnotationAttributes(type, true);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -704,7 +912,52 @@ public abstract class AnnotationUtils {
|
|||
* @since 4.3.2
|
||||
*/
|
||||
public static void registerDefaultValues(AnnotationAttributes attributes) {
|
||||
InternalAnnotationUtils.registerDefaultValues(attributes);
|
||||
AnnotationAttributes copy = new AnnotationAttributes(attributes);
|
||||
MigrateMethod.fromCall(()->
|
||||
InternalAnnotationUtils.registerDefaultValues(copy)
|
||||
).withArgumentCheck(copy, attributes).to(()-> {
|
||||
Class<? extends Annotation> annotationType = attributes.annotationType();
|
||||
if (annotationType != null && Modifier.isPublic(annotationType.getModifiers())) {
|
||||
getDefaultValues(annotationType).forEach(attributes::putIfAbsent);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static Map<String, DefaultValueHolder> getDefaultValues(
|
||||
Class<? extends Annotation> annotationType) {
|
||||
|
||||
return defaultValuesCache.computeIfAbsent(annotationType,
|
||||
AnnotationUtils::computeDefaultValues);
|
||||
}
|
||||
|
||||
private static Map<String, DefaultValueHolder> computeDefaultValues(
|
||||
Class<? extends Annotation> annotationType) {
|
||||
|
||||
AttributeMethods methods = AttributeMethods.forAnnotationType(annotationType);
|
||||
if (!methods.hasDefaultValueMethod()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<String, DefaultValueHolder> result = new LinkedHashMap<>(methods.size());
|
||||
if (!methods.hasNestedAnnotation()) {
|
||||
// Use simpler method if there are no nested annotations
|
||||
for (int i = 0; i < methods.size(); i++) {
|
||||
Method method = methods.get(i);
|
||||
Object defaultValue = method.getDefaultValue();
|
||||
if(defaultValue != null) {
|
||||
result.put(method.getName(), new DefaultValueHolder(defaultValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// If we have nested annotations, we need them as nested maps
|
||||
AnnotationAttributes attributes = MergedAnnotation.from(annotationType).asMap(
|
||||
getAnnotationAttributesFactory(annotationType.getClassLoader()),
|
||||
MapValues.ANNOTATION_TO_MAP);
|
||||
for (Map.Entry<String, Object> element : attributes.entrySet()) {
|
||||
result.put(element.getKey(), new DefaultValueHolder(element.getValue()));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -721,13 +974,91 @@ public abstract class AnnotationUtils {
|
|||
* compatibility with {@link org.springframework.core.type.AnnotationMetadata})
|
||||
* or to preserve them as Class references
|
||||
* @since 4.3.2
|
||||
* @see #postProcessAnnotationAttributes(Object, AnnotationAttributes, boolean, boolean)
|
||||
* @see #getDefaultValue(Class, String)
|
||||
*/
|
||||
public static void postProcessAnnotationAttributes(@Nullable Object annotatedElement,
|
||||
AnnotationAttributes attributes, boolean classValuesAsString) {
|
||||
InternalAnnotationUtils.postProcessAnnotationAttributes(annotatedElement,
|
||||
attributes, classValuesAsString);
|
||||
|
||||
AnnotationAttributes copy = new AnnotationAttributes(attributes);
|
||||
MigrateMethod.fromCall(() ->
|
||||
InternalAnnotationUtils.postProcessAnnotationAttributes(annotatedElement, copy,
|
||||
classValuesAsString)
|
||||
).withArgumentCheck(copy, attributes).to(()-> {
|
||||
if (attributes == null || attributes.annotationType() == null) {
|
||||
return;
|
||||
}
|
||||
if (!attributes.validated) {
|
||||
Class<? extends Annotation> annotationType = attributes.annotationType();
|
||||
if (annotationType != null) {
|
||||
AnnotationTypeMapping mapping = AnnotationTypeMappings
|
||||
.forAnnotationType(annotationType).get(0);
|
||||
for (int i = 0; i < mapping.getMirrorSets().size(); i++) {
|
||||
MirrorSet mirrorSet = mapping.getMirrorSets().get(i);
|
||||
int resolved = mirrorSet.resolve(attributes.displayName, attributes,
|
||||
AnnotationUtils::getAttributeValueForMirrorResolution);
|
||||
if (resolved != -1) {
|
||||
Method attribute = mapping.getAttributes().get(resolved);
|
||||
Object value = attributes.get(attribute.getName());
|
||||
for (int j = 0; j < mirrorSet.size(); j++) {
|
||||
Method mirror = mirrorSet.get(j);
|
||||
if (mirror != attribute) {
|
||||
attributes.put(mirror.getName(),
|
||||
adaptValue(annotatedElement, value, classValuesAsString));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Map.Entry<String, Object> attributeEntry : attributes.entrySet()) {
|
||||
String attributeName = attributeEntry.getKey();
|
||||
Object value = attributeEntry.getValue();
|
||||
if (value instanceof DefaultValueHolder) {
|
||||
value = ((DefaultValueHolder) value).defaultValue;
|
||||
attributes.put(attributeName,
|
||||
adaptValue(annotatedElement, value, classValuesAsString));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static Object getAttributeValueForMirrorResolution(Method attribute,
|
||||
Object attributes) {
|
||||
|
||||
Object result = ((AnnotationAttributes) attributes).get(attribute.getName());
|
||||
return result instanceof DefaultValueHolder ?
|
||||
((DefaultValueHolder) result).defaultValue :
|
||||
result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static Object adaptValue(@Nullable Object annotatedElement, @Nullable Object value,
|
||||
boolean classValuesAsString) {
|
||||
|
||||
if (classValuesAsString) {
|
||||
if (value instanceof Class) {
|
||||
return ((Class<?>) value).getName();
|
||||
}
|
||||
if (value instanceof Class[]) {
|
||||
return Arrays.stream((Class<?>[]) value).map(Class::getName).toArray(
|
||||
String[]::new);
|
||||
}
|
||||
}
|
||||
if (value instanceof Annotation) {
|
||||
Annotation annotation = (Annotation) value;
|
||||
return MergedAnnotation.from(annotatedElement, annotation).synthesize();
|
||||
}
|
||||
if (value instanceof Annotation[]) {
|
||||
Annotation[] annotations = (Annotation[]) value;
|
||||
Annotation[] synthesized = (Annotation[]) Array.newInstance(
|
||||
annotations.getClass().getComponentType(), annotations.length);
|
||||
for (int i = 0; i < annotations.length; i++) {
|
||||
synthesized[i] = MergedAnnotation.from(annotatedElement,
|
||||
annotations[i]).synthesize();
|
||||
}
|
||||
return synthesized;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -741,7 +1072,7 @@ public abstract class AnnotationUtils {
|
|||
*/
|
||||
@Nullable
|
||||
public static Object getValue(Annotation annotation) {
|
||||
return InternalAnnotationUtils.getValue(annotation);
|
||||
return getValue(annotation, VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -752,10 +1083,11 @@ public abstract class AnnotationUtils {
|
|||
* value cannot be retrieved due to an {@link AnnotationConfigurationException},
|
||||
* in which case such an exception will be rethrown
|
||||
* @see #getValue(Annotation)
|
||||
* @see #rethrowAnnotationConfigurationException(Throwable)
|
||||
*/
|
||||
@Nullable
|
||||
public static Object getValue(@Nullable Annotation annotation, @Nullable String attributeName) {
|
||||
public static Object getValue(@Nullable Annotation annotation,
|
||||
@Nullable String attributeName) {
|
||||
|
||||
return InternalAnnotationUtils.getValue(annotation, attributeName);
|
||||
}
|
||||
|
||||
|
|
@ -768,7 +1100,7 @@ public abstract class AnnotationUtils {
|
|||
*/
|
||||
@Nullable
|
||||
public static Object getDefaultValue(Annotation annotation) {
|
||||
return InternalAnnotationUtils.getDefaultValue(annotation);
|
||||
return getDefaultValue(annotation, VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -779,8 +1111,12 @@ public abstract class AnnotationUtils {
|
|||
* @see #getDefaultValue(Class, String)
|
||||
*/
|
||||
@Nullable
|
||||
public static Object getDefaultValue(@Nullable Annotation annotation, @Nullable String attributeName) {
|
||||
return InternalAnnotationUtils.getDefaultValue(annotation, attributeName);
|
||||
public static Object getDefaultValue(@Nullable Annotation annotation,
|
||||
@Nullable String attributeName) {
|
||||
|
||||
return annotation != null ?
|
||||
getDefaultValue(annotation.annotationType(), attributeName) :
|
||||
null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -792,7 +1128,7 @@ public abstract class AnnotationUtils {
|
|||
*/
|
||||
@Nullable
|
||||
public static Object getDefaultValue(Class<? extends Annotation> annotationType) {
|
||||
return InternalAnnotationUtils.getDefaultValue(annotationType);
|
||||
return getDefaultValue(annotationType, VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -805,8 +1141,18 @@ public abstract class AnnotationUtils {
|
|||
*/
|
||||
@Nullable
|
||||
public static Object getDefaultValue(
|
||||
@Nullable Class<? extends Annotation> annotationType, @Nullable String attributeName) {
|
||||
return InternalAnnotationUtils.getDefaultValue(annotationType, attributeName);
|
||||
@Nullable Class<? extends Annotation> annotationType,
|
||||
@Nullable String attributeName) {
|
||||
|
||||
return MigrateMethod.from(() ->
|
||||
InternalAnnotationUtils.getDefaultValue(annotationType, attributeName)
|
||||
).toNullable(() -> {
|
||||
if (annotationType == null || !StringUtils.hasText(attributeName)) {
|
||||
return null;
|
||||
}
|
||||
return MergedAnnotation.from(annotationType)
|
||||
.getDefaultValue(attributeName).orElse(null);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -828,7 +1174,8 @@ public abstract class AnnotationUtils {
|
|||
*/
|
||||
public static <A extends Annotation> A synthesizeAnnotation(
|
||||
A annotation, @Nullable AnnotatedElement annotatedElement) {
|
||||
return InternalAnnotationUtils.synthesizeAnnotation(annotation, annotatedElement);
|
||||
|
||||
return synthesizeAnnotation(annotation, (Object) annotatedElement);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -860,10 +1207,22 @@ public abstract class AnnotationUtils {
|
|||
* @see #getAnnotationAttributes(AnnotatedElement, Annotation)
|
||||
* @see #getAnnotationAttributes(AnnotatedElement, Annotation, boolean, boolean)
|
||||
*/
|
||||
public static <A extends Annotation> A synthesizeAnnotation(Map<String, Object> attributes,
|
||||
Class<A> annotationType, @Nullable AnnotatedElement annotatedElement) {
|
||||
return InternalAnnotationUtils.synthesizeAnnotation(attributes, annotationType,
|
||||
annotatedElement);
|
||||
public static <A extends Annotation> A synthesizeAnnotation(
|
||||
Map<String, Object> attributes, Class<A> annotationType,
|
||||
@Nullable AnnotatedElement annotatedElement) {
|
||||
|
||||
return MigrateMethod.from(()->
|
||||
InternalAnnotationUtils.synthesizeAnnotation(attributes, annotationType,
|
||||
annotatedElement)
|
||||
).to(()-> {
|
||||
try {
|
||||
return MergedAnnotation.from(annotatedElement, annotationType, attributes)
|
||||
.synthesize();
|
||||
}
|
||||
catch (NoSuchElementException | IllegalStateException ex) {
|
||||
throw new IllegalArgumentException(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -882,14 +1241,15 @@ public abstract class AnnotationUtils {
|
|||
* @see #synthesizeAnnotation(Annotation, AnnotatedElement)
|
||||
*/
|
||||
public static <A extends Annotation> A synthesizeAnnotation(Class<A> annotationType) {
|
||||
return InternalAnnotationUtils.synthesizeAnnotation(annotationType);
|
||||
return synthesizeAnnotation(Collections.emptyMap(), annotationType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* <em>Synthesize</em> an array of annotations from the supplied array
|
||||
* of {@code annotations} by creating a new array of the same size and
|
||||
* type and populating it with {@linkplain #synthesizeAnnotation(Annotation)
|
||||
* synthesized} versions of the annotations from the input array.
|
||||
* type and populating it with {@linkplain #synthesizeAnnotation(Annotation,
|
||||
* AnnotatedElement) synthesized} versions of the annotations from the input
|
||||
* array.
|
||||
* @param annotations the array of annotations to synthesize
|
||||
* @param annotatedElement the element that is annotated with the supplied
|
||||
* array of annotations; may be {@code null} if unknown
|
||||
|
|
@ -904,8 +1264,30 @@ public abstract class AnnotationUtils {
|
|||
static Annotation[] synthesizeAnnotationArray(Annotation[] annotations,
|
||||
@Nullable Object annotatedElement) {
|
||||
|
||||
return InternalAnnotationUtils.synthesizeAnnotationArray(annotations,
|
||||
annotatedElement);
|
||||
if (AnnotationsScanner.hasPlainJavaAnnotationsOnly(annotatedElement)) {
|
||||
return annotations;
|
||||
}
|
||||
Annotation[] synthesized = (Annotation[]) Array.newInstance(
|
||||
annotations.getClass().getComponentType(), annotations.length);
|
||||
for (int i = 0; i < annotations.length; i++) {
|
||||
synthesized[i] = synthesizeAnnotation(annotations[i], annotatedElement);
|
||||
}
|
||||
return synthesized;
|
||||
}
|
||||
|
||||
private static <A extends Annotation> A synthesizeAnnotation(A annotation,
|
||||
@Nullable Object annotatedElement) {
|
||||
|
||||
return MigrateMethod.from(()->
|
||||
InternalAnnotationUtils.synthesizeAnnotation(annotation, annotatedElement)
|
||||
).withSkippedOriginalExceptionCheck().to(() -> {
|
||||
if (annotation instanceof SynthesizedAnnotation ||
|
||||
AnnotationsScanner.hasPlainJavaAnnotationsOnly(annotatedElement) ||
|
||||
AnnotationFilter.PLAIN.matches(annotation)) {
|
||||
return annotation;
|
||||
}
|
||||
return MergedAnnotation.from(annotatedElement, annotation).synthesize();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -916,4 +1298,10 @@ public abstract class AnnotationUtils {
|
|||
InternalAnnotationUtils.clearCache();
|
||||
}
|
||||
|
||||
private static <A extends Annotation> boolean isSingleLevelPresent(
|
||||
MergedAnnotation<A> mergedAnnotation) {
|
||||
int depth = mergedAnnotation.getDepth();
|
||||
return depth == 0 || depth == 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,293 @@
|
|||
/*
|
||||
* Copyright 2002-2019 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
|
||||
*
|
||||
* http://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.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.core.annotation.InternalAnnotationUtils.DefaultValueHolder;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Internal class used to help migrate annotation util methods to a new implementation.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 5.2
|
||||
*/
|
||||
final class MigrateMethod {
|
||||
|
||||
private MigrateMethod() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link ReplacementMethod} builder for the deprecated method.
|
||||
* @param originalMethod the original method being migrated
|
||||
* @return a replacement builder.
|
||||
*/
|
||||
static <T> ReplacementMethod<T> from(Supplier<T> originalMethod) {
|
||||
return new ReplacementMethod<>(originalMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link ReplacementVoidMethod} for the deprecated method.
|
||||
* @param originalMethod the original method being migrated
|
||||
* @return a replacement builder.
|
||||
*/
|
||||
static ReplacementVoidMethod fromCall(Runnable originalMethod) {
|
||||
return new ReplacementVoidMethod(originalMethod);
|
||||
}
|
||||
|
||||
private static boolean isEquivalent(@Nullable Object result, @Nullable Object expectedResult) {
|
||||
if (ObjectUtils.nullSafeEquals(result, expectedResult)) {
|
||||
return true;
|
||||
}
|
||||
if (result == null && String.valueOf(expectedResult).startsWith(
|
||||
"@org.springframework.lang.")) {
|
||||
// Original methods don't filter spring annotation but we do
|
||||
return true;
|
||||
}
|
||||
if (result == null || expectedResult == null) {
|
||||
return false;
|
||||
}
|
||||
if (result instanceof DefaultValueHolder && expectedResult instanceof DefaultValueHolder) {
|
||||
return isEquivalent(((DefaultValueHolder) result).defaultValue,
|
||||
((DefaultValueHolder) expectedResult).defaultValue);
|
||||
}
|
||||
if (result instanceof Map && expectedResult instanceof Map) {
|
||||
return isEquivalentMap((Map<?, ?>) result, (Map<?, ?>) expectedResult);
|
||||
}
|
||||
if (result instanceof List && expectedResult instanceof List) {
|
||||
return isEquivalentList((List<?>) result, (List<?>) expectedResult);
|
||||
}
|
||||
if (result instanceof Object[] && expectedResult instanceof Object[]) {
|
||||
return isEquivalentArray((Object[]) result, (Object[]) expectedResult);
|
||||
}
|
||||
if (result instanceof Object[]) {
|
||||
if (isEquivalentArray((Object[]) result, new Object[] { expectedResult })) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!(result instanceof Object[]) && expectedResult instanceof Object[]) {
|
||||
if (isEquivalentArray(new Object[] { result }, (Object[]) expectedResult)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isEquivalentMap(Map<?, ?> result, Map<?, ?> expectedResult) {
|
||||
if (result.size() != expectedResult.size()) {
|
||||
return false;
|
||||
}
|
||||
for (Map.Entry<?, ?> entry : result.entrySet()) {
|
||||
if (!expectedResult.containsKey(entry.getKey())) {
|
||||
return false;
|
||||
}
|
||||
if (!isEquivalent(entry.getValue(), expectedResult.get(entry.getKey()))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isEquivalentList(List<?> result, List<?> expectedResult) {
|
||||
if (result.size() != expectedResult.size()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < result.size(); i++) {
|
||||
if (!isEquivalent(result.get(i), expectedResult.get(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isEquivalentArray(Object[] result, Object[] expectedResult) {
|
||||
if (result.length != expectedResult.length) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
if (!isEquivalent(result[i], expectedResult[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder to complete replacement details for a deprecated annotation method.
|
||||
* @param <T> the return type
|
||||
*/
|
||||
static class ReplacementMethod<T> {
|
||||
|
||||
private final Supplier<T> originalMethod;
|
||||
|
||||
@Nullable
|
||||
private Supplier<String> description;
|
||||
|
||||
private boolean skipOriginalExceptionCheck;
|
||||
|
||||
private BooleanSupplier skipEquivalentCheck = () -> false;
|
||||
|
||||
ReplacementMethod(Supplier<T> deprecatedMethod) {
|
||||
this.originalMethod = deprecatedMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a description for the method.
|
||||
* @param description a description supplier
|
||||
* @return this instance
|
||||
*/
|
||||
public ReplacementMethod<T> withDescription(Supplier<String> description) {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ReplacementMethod<T> withSkippedOriginalExceptionCheck() {
|
||||
this.skipOriginalExceptionCheck = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ReplacementMethod<T> withSkippedEquivalentCheck(BooleanSupplier supplier) {
|
||||
this.skipEquivalentCheck = supplier;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide the replacement method that should be used instead of the deprecated
|
||||
* one. The replacement method is called, and when appropriate the result is
|
||||
* checked against the deprecated method.
|
||||
* @param replacementMethod the replacement method
|
||||
* @return the result of the replacement method
|
||||
*/
|
||||
public T to(Supplier<T> replacementMethod) {
|
||||
T result = toNullable(replacementMethod);
|
||||
if (result == null) {
|
||||
throw new IllegalStateException("Unexpected null result");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide the replacement method that should be used instead of the deprecated
|
||||
* one. The replacement method is called, and when appropriate the result is
|
||||
* checked against the deprecated method.
|
||||
* @param replacementMethod the replacement method
|
||||
* @return the result of the replacement method
|
||||
*/
|
||||
@Nullable
|
||||
public T toNullable(Supplier<T> replacementMethod) {
|
||||
T result = tryInvoke(replacementMethod);
|
||||
T expectedResult = this.originalMethod.get();
|
||||
if (!isEquivalent(result, expectedResult)) {
|
||||
if (this.skipEquivalentCheck.getAsBoolean()) {
|
||||
return expectedResult;
|
||||
}
|
||||
String description = (this.description != null ? " [" +
|
||||
this.description.get() + "]" : "");
|
||||
throw new IllegalStateException("Expected " + expectedResult +
|
||||
" got " + result + description);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private T tryInvoke(Supplier<T> replacementMethod) {
|
||||
try {
|
||||
return replacementMethod.get();
|
||||
}
|
||||
catch (RuntimeException expected) {
|
||||
try {
|
||||
T expectedResult = this.originalMethod.get();
|
||||
if (this.skipOriginalExceptionCheck) {
|
||||
return expectedResult;
|
||||
}
|
||||
throw new Error("Expected exception not thrown", expected);
|
||||
}
|
||||
catch (RuntimeException actual) {
|
||||
if (!expected.getClass().isInstance(actual)) {
|
||||
throw new Error(
|
||||
"Exception is not " + expected.getClass().getName(),
|
||||
actual);
|
||||
}
|
||||
throw actual;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder to complete replacement details for a deprecated annotation method that
|
||||
* returns void.
|
||||
*/
|
||||
static class ReplacementVoidMethod {
|
||||
|
||||
private final Runnable originalMethod;
|
||||
|
||||
private final List<Object[]> argumentChecks = new ArrayList<>();
|
||||
|
||||
public ReplacementVoidMethod(Runnable originalMethod) {
|
||||
this.originalMethod = originalMethod;
|
||||
}
|
||||
|
||||
public ReplacementVoidMethod withArgumentCheck(Object originalArgument,
|
||||
Object replacementArgument) {
|
||||
this.argumentChecks.add(
|
||||
new Object[] { originalArgument, replacementArgument });
|
||||
return this;
|
||||
}
|
||||
|
||||
public void to(Runnable replacementMethod) {
|
||||
tryInvoke(this.originalMethod);
|
||||
replacementMethod.run();
|
||||
for (Object[] arguments : this.argumentChecks) {
|
||||
Object expectedArgument = arguments[0];
|
||||
Object actualArgument = arguments[1];
|
||||
Assert.state(isEquivalent(actualArgument, expectedArgument),
|
||||
() -> "Expected argument mutation of " + expectedArgument
|
||||
+ " got " + actualArgument);
|
||||
}
|
||||
}
|
||||
|
||||
private void tryInvoke(Runnable replacementMethod) {
|
||||
try {
|
||||
replacementMethod.run();
|
||||
}
|
||||
catch (RuntimeException expected) {
|
||||
try {
|
||||
this.originalMethod.run();
|
||||
throw new Error("Expected exception not thrown", expected);
|
||||
}
|
||||
catch (RuntimeException actual) {
|
||||
if (!expected.getClass().isInstance(actual)) {
|
||||
throw new Error(
|
||||
"Exception is not " + expected.getClass().getName(),
|
||||
actual);
|
||||
}
|
||||
throw actual;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 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.
|
||||
|
|
@ -459,7 +459,9 @@ public class AnnotatedElementUtilsTests {
|
|||
exception.expectMessage(either(
|
||||
containsString("values of [{duplicateDeclaration}] and [{requiredLocationsDeclaration}]")).or(
|
||||
containsString("values of [{requiredLocationsDeclaration}] and [{duplicateDeclaration}]")));
|
||||
exception.expectMessage(containsString("but only one is permitted"));
|
||||
exception.expectMessage(either(
|
||||
containsString("but only one is permitted")).or(
|
||||
containsString("Different @AliasFor mirror values for annotation")));
|
||||
getMergedAnnotationAttributes(element, ContextConfig.class);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -562,7 +562,9 @@ public class AnnotationUtilsTests {
|
|||
exception.expect(AnnotationConfigurationException.class);
|
||||
exception.expectMessage(startsWith("Attribute 'value' in"));
|
||||
exception.expectMessage(containsString(BrokenContextConfig.class.getName()));
|
||||
exception.expectMessage(containsString("@AliasFor [location]"));
|
||||
exception.expectMessage(either(
|
||||
containsString("@AliasFor [location]")).or(
|
||||
containsString("@AliasFor 'location'")));
|
||||
|
||||
getRepeatableAnnotations(BrokenConfigHierarchyTestCase.class, BrokenContextConfig.class, BrokenHierarchy.class);
|
||||
}
|
||||
|
|
@ -897,7 +899,9 @@ public class AnnotationUtilsTests {
|
|||
exception.expect(AnnotationConfigurationException.class);
|
||||
exception.expectMessage(startsWith("In @AliasFor declared on attribute 'foo' in annotation"));
|
||||
exception.expectMessage(containsString(AliasForWithDuplicateAttributeDeclaration.class.getName()));
|
||||
exception.expectMessage(containsString("attribute 'attribute' and its alias 'value' are present with values of [baz] and [bar]"));
|
||||
exception.expectMessage(anyOf(
|
||||
containsString("attribute 'attribute' and its alias 'value' are present with values of [baz] and [bar]"),
|
||||
containsString("attribute 'attribute' and its alias 'value' are present with values of 'bar' and 'baz'")));
|
||||
InternalAnnotationUtils.synthesizeAnnotation(annotation);
|
||||
}
|
||||
|
||||
|
|
@ -905,9 +909,14 @@ public class AnnotationUtilsTests {
|
|||
public void synthesizeAnnotationWithAttributeAliasForNonexistentAttribute() throws Exception {
|
||||
AliasForNonexistentAttribute annotation = AliasForNonexistentAttributeClass.class.getAnnotation(AliasForNonexistentAttribute.class);
|
||||
exception.expect(AnnotationConfigurationException.class);
|
||||
exception.expectMessage(startsWith("Attribute 'foo' in"));
|
||||
exception.expectMessage(containsString(AliasForNonexistentAttribute.class.getName()));
|
||||
exception.expectMessage(containsString("is declared as an @AliasFor nonexistent attribute 'bar'"));
|
||||
exception.expectMessage(either(allOf(
|
||||
startsWith("Attribute 'foo' in"),
|
||||
containsString(AliasForNonexistentAttribute.class.getName()),
|
||||
containsString("is declared as an @AliasFor nonexistent attribute 'bar'"))
|
||||
).or(
|
||||
containsString("@AliasFor declaration on attribute 'foo' in annotation ["
|
||||
+ AliasForNonexistentAttribute.class.getName()
|
||||
+ "] declares an alias for 'bar' which is not present")));
|
||||
InternalAnnotationUtils.synthesizeAnnotation(annotation);
|
||||
}
|
||||
|
||||
|
|
@ -916,9 +925,9 @@ public class AnnotationUtilsTests {
|
|||
AliasForWithoutMirroredAliasFor annotation =
|
||||
AliasForWithoutMirroredAliasForClass.class.getAnnotation(AliasForWithoutMirroredAliasFor.class);
|
||||
exception.expect(AnnotationConfigurationException.class);
|
||||
exception.expectMessage(startsWith("Attribute 'bar' in"));
|
||||
exception.expectMessage(containsString(AliasForWithoutMirroredAliasFor.class.getName()));
|
||||
exception.expectMessage(containsString("@AliasFor [foo]"));
|
||||
exception.expectMessage(allOf(startsWith("Attribute 'bar' in"),
|
||||
containsString(AliasForWithoutMirroredAliasFor.class.getName()),
|
||||
either(containsString("@AliasFor [foo]")).or(containsString("@AliasFor 'foo'"))));
|
||||
InternalAnnotationUtils.synthesizeAnnotation(annotation);
|
||||
}
|
||||
|
||||
|
|
@ -929,8 +938,10 @@ public class AnnotationUtilsTests {
|
|||
exception.expect(AnnotationConfigurationException.class);
|
||||
exception.expectMessage(startsWith("Attribute 'bar' in"));
|
||||
exception.expectMessage(containsString(AliasForWithMirroredAliasForWrongAttribute.class.getName()));
|
||||
exception.expectMessage(either(containsString("must be declared as an @AliasFor [foo], not [quux]")).
|
||||
or(containsString("is declared as an @AliasFor nonexistent attribute 'quux'")));
|
||||
exception.expectMessage(anyOf(
|
||||
containsString("must be declared as an @AliasFor [foo], not [quux]"),
|
||||
containsString("is declared as an @AliasFor nonexistent attribute 'quux'"),
|
||||
containsString("must be declared as an @AliasFor 'foo', not attribute 'quux'")));
|
||||
InternalAnnotationUtils.synthesizeAnnotation(annotation);
|
||||
}
|
||||
|
||||
|
|
@ -980,7 +991,7 @@ public class AnnotationUtilsTests {
|
|||
exception.expect(AnnotationConfigurationException.class);
|
||||
exception.expectMessage(startsWith("@AliasFor declaration on attribute 'xmlConfigFile' in annotation"));
|
||||
exception.expectMessage(containsString(AliasedComposedContextConfigNotMetaPresent.class.getName()));
|
||||
exception.expectMessage(containsString("declares an alias for attribute 'location' in meta-annotation"));
|
||||
exception.expectMessage(containsString("declares an alias for attribute 'location'"));
|
||||
exception.expectMessage(containsString(ContextConfig.class.getName()));
|
||||
exception.expectMessage(containsString("not meta-present"));
|
||||
InternalAnnotationUtils.synthesizeAnnotation(annotation);
|
||||
|
|
@ -1133,21 +1144,16 @@ public class AnnotationUtilsTests {
|
|||
ImplicitAliasesWithDuplicateValuesContextConfig config = clazz.getAnnotation(annotationType);
|
||||
assertNotNull(config);
|
||||
|
||||
ImplicitAliasesWithDuplicateValuesContextConfig synthesizedConfig = synthesizeAnnotation(config, clazz);
|
||||
assertNotNull(synthesizedConfig);
|
||||
|
||||
exception.expect(AnnotationConfigurationException.class);
|
||||
exception.expectMessage(startsWith("In annotation"));
|
||||
exception.expectMessage(either(startsWith("In annotation")).or(startsWith("Different @AliasFor mirror values")));
|
||||
exception.expectMessage(containsString(annotationType.getName()));
|
||||
exception.expectMessage(containsString("declared on class"));
|
||||
exception.expectMessage(containsString(clazz.getName()));
|
||||
exception.expectMessage(containsString("and synthesized from"));
|
||||
exception.expectMessage(either(containsString("attribute 'location1' and its alias 'location2'")).or(
|
||||
containsString("attribute 'location2' and its alias 'location1'")));
|
||||
exception.expectMessage(either(containsString("are present with values of [1] and [2]")).or(
|
||||
containsString("are present with values of [2] and [1]")));
|
||||
|
||||
synthesizedConfig.location1();
|
||||
exception.expectMessage(either(containsString("with values of [1] and [2]")).or(
|
||||
containsString("with values of [2] and [1]")));
|
||||
synthesizeAnnotation(config, clazz).location1();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -1241,8 +1247,8 @@ public class AnnotationUtilsTests {
|
|||
|
||||
@Test
|
||||
public void synthesizeAnnotationWithAttributeAliasesWithDifferentValues() throws Exception {
|
||||
ContextConfig contextConfig = InternalAnnotationUtils.synthesizeAnnotation(ContextConfigMismatch.class.getAnnotation(ContextConfig.class));
|
||||
exception.expect(AnnotationConfigurationException.class);
|
||||
ContextConfig contextConfig = InternalAnnotationUtils.synthesizeAnnotation(ContextConfigMismatch.class.getAnnotation(ContextConfig.class));
|
||||
getValue(contextConfig);
|
||||
}
|
||||
|
||||
|
|
@ -1306,23 +1312,29 @@ public class AnnotationUtilsTests {
|
|||
|
||||
private void assertMissingTextAttribute(Map<String, Object> attributes) {
|
||||
exception.expect(IllegalArgumentException.class);
|
||||
exception.expectMessage(startsWith("Attributes map"));
|
||||
exception.expectMessage(containsString("returned null for required attribute 'text'"));
|
||||
exception.expectMessage(containsString("defined by annotation type [" + AnnotationWithoutDefaults.class.getName() + "]"));
|
||||
exception.expectMessage(either(allOf(startsWith("Attributes map"),
|
||||
containsString("returned null for required attribute 'text'"),
|
||||
containsString("defined by annotation type ["
|
||||
+ AnnotationWithoutDefaults.class.getName() + "]"))).or(
|
||||
containsString(
|
||||
"No value found for attribute named 'text' in merged annotation")));
|
||||
synthesizeAnnotation(attributes, AnnotationWithoutDefaults.class, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void synthesizeAnnotationFromMapWithAttributeOfIncorrectType() throws Exception {
|
||||
Map<String, Object> map = Collections.singletonMap(VALUE, 42L);
|
||||
|
||||
exception.expect(IllegalArgumentException.class);
|
||||
exception.expectMessage(startsWith("Attributes map"));
|
||||
exception.expectMessage(containsString("returned a value of type [java.lang.Long]"));
|
||||
exception.expectMessage(containsString("for attribute 'value'"));
|
||||
exception.expectMessage(containsString("but a value of type [java.lang.String] is required"));
|
||||
exception.expectMessage(containsString("as defined by annotation type [" + Component.class.getName() + "]"));
|
||||
|
||||
exception.expectMessage(either(allOf(startsWith("Attributes map"),
|
||||
containsString("returned a value of type [java.lang.Long]"),
|
||||
containsString("for attribute 'value'"),
|
||||
containsString("but a value of type [java.lang.String] is required"),
|
||||
containsString("as defined by annotation type ["
|
||||
+ Component.class.getName() + "]"))).or(
|
||||
containsString("Attribute 'value' in annotation "
|
||||
+ Component.class.getName()
|
||||
+ " should be of type "
|
||||
+ "java.lang.String but a java.lang.Long value was returned")));
|
||||
synthesizeAnnotation(map, Component.class, null);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2019 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.
|
||||
|
|
@ -79,7 +79,8 @@ public class SqlScriptsTestExecutionListenerTests {
|
|||
containsString("attribute 'scripts' and its alias 'value'")));
|
||||
exception.expectMessage(either(containsString("values of [{foo}] and [{bar}]")).or(
|
||||
containsString("values of [{bar}] and [{foo}]")));
|
||||
exception.expectMessage(containsString("but only one is permitted"));
|
||||
exception.expectMessage(either(containsString("but only one is permitted")).or(
|
||||
containsString("Different @AliasFor mirror values")));
|
||||
listener.beforeTestMethod(testContext);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2019 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.
|
||||
|
|
@ -73,7 +73,9 @@ public class ContextLoaderUtilsConfigurationAttributesTests extends AbstractCont
|
|||
exception.expectMessage(either(
|
||||
containsString("values of [{x}] and [{y}]")).or(
|
||||
containsString("values of [{y}] and [{x}]")));
|
||||
exception.expectMessage(containsString("but only one is permitted"));
|
||||
exception.expectMessage(either(
|
||||
containsString("Different @AliasFor mirror values")).or(
|
||||
containsString("but only one is permitted")));
|
||||
resolveContextConfigurationAttributes(ConflictingLocations.class);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue