Polishing

This commit is contained in:
Juergen Hoeller 2019-03-26 16:13:51 +01:00
parent 210b178922
commit 635305647c
6 changed files with 78 additions and 116 deletions

View File

@ -668,12 +668,14 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
@Nullable
public <A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType)
throws NoSuchBeanDefinitionException {
return findMergedAnnotationOnBean(beanName, annotationType).synthesize(
MergedAnnotation::isPresent).orElse(null);
return findMergedAnnotationOnBean(beanName, annotationType)
.synthesize(MergedAnnotation::isPresent).orElse(null);
}
private <A extends Annotation> MergedAnnotation<A> findMergedAnnotationOnBean(
String beanName, Class<A> annotationType) {
Class<?> beanType = getType(beanName);
if (beanType != null) {
MergedAnnotation<A> annotation = MergedAnnotations.from(beanType,

View File

@ -76,27 +76,19 @@ final class AnnotationTypeMapping {
private final Set<Method> claimedAliases = new HashSet<>();
AnnotationTypeMapping(Class<? extends Annotation> annotationType) {
this(null, annotationType, null);
}
AnnotationTypeMapping(AnnotationTypeMapping parent, Annotation annotation) {
this(parent, annotation.annotationType(), annotation);
}
AnnotationTypeMapping(@Nullable AnnotationTypeMapping parent,
Class<? extends Annotation> annotationType, @Nullable Annotation annotation) {
this.parent = parent;
this.root = parent != null ? parent.getRoot() : this;
this.depth = parent == null ? 0 : parent.getDepth() + 1;
this.root = (parent != null ? parent.getRoot() : this);
this.depth = (parent == null ? 0 : parent.getDepth() + 1);
this.annotationType = annotationType;
this.annotation = annotation;
this.attributes = AttributeMethods.forAnnotationType(annotationType);
this.mirrorSets = new MirrorSets();
this.aliasMappings = filledIntArray(this.attributes.size(), -1);
this.conventionMappings = filledIntArray(this.attributes.size(), -1);
this.annotationValueMappings = filledIntArray(this.attributes.size(), -1);
this.aliasMappings = filledIntArray(this.attributes.size());
this.conventionMappings = filledIntArray(this.attributes.size());
this.annotationValueMappings = filledIntArray(this.attributes.size());
this.annotationValueSource = new AnnotationTypeMapping[this.attributes.size()];
this.aliasedBy = resolveAliasedForTargets();
processAliases();
@ -109,12 +101,10 @@ final class AnnotationTypeMapping {
Map<Method, List<Method>> aliasedBy = new HashMap<>();
for (int i = 0; i < this.attributes.size(); i++) {
Method attribute = this.attributes.get(i);
AliasFor aliasFor = AnnotationsScanner.getDeclaredAnnotation(attribute,
AliasFor.class);
AliasFor aliasFor = AnnotationsScanner.getDeclaredAnnotation(attribute, AliasFor.class);
if (aliasFor != null) {
Method target = resolveAliasTarget(attribute, aliasFor);
aliasedBy.computeIfAbsent(target, key -> new ArrayList<>()).add(
attribute);
aliasedBy.computeIfAbsent(target, key -> new ArrayList<>()).add(attribute);
}
}
return Collections.unmodifiableMap(aliasedBy);
@ -125,12 +115,10 @@ final class AnnotationTypeMapping {
}
private Method resolveAliasTarget(Method attribute, AliasFor aliasFor, boolean checkAliasPair) {
if (StringUtils.hasText(aliasFor.value()) &&
StringUtils.hasText(aliasFor.attribute())) {
if (StringUtils.hasText(aliasFor.value()) && StringUtils.hasText(aliasFor.attribute())) {
throw new AnnotationConfigurationException(String.format(
"In @AliasFor declared on %s, attribute 'attribute' and its alias "
+ "'value' are present with values of '%s' and '%s', but "
+ "only one is permitted.",
"In @AliasFor declared on %s, attribute 'attribute' and its alias 'value' " +
"are present with values of '%s' and '%s', but only one is permitted.",
AttributeMethods.describe(attribute), aliasFor.attribute(),
aliasFor.value()));
}
@ -145,13 +133,11 @@ final class AnnotationTypeMapping {
if (!StringUtils.hasLength(targetAttributeName)) {
targetAttributeName = attribute.getName();
}
Method target = AttributeMethods.forAnnotationType(targetAnnotation)
.get(targetAttributeName);
Method target = AttributeMethods.forAnnotationType(targetAnnotation).get(targetAttributeName);
if (target == null) {
if (targetAnnotation == this.annotationType) {
throw new AnnotationConfigurationException(String.format(
"@AliasFor declaration on %s declares an "
+ "alias for '%s' which is not present.",
"@AliasFor declaration on %s declares an alias for '%s' which is not present.",
AttributeMethods.describe(attribute), targetAttributeName));
}
throw new AnnotationConfigurationException(String.format(
@ -161,9 +147,8 @@ final class AnnotationTypeMapping {
}
if (target == attribute) {
throw new AnnotationConfigurationException(String.format(
"@AliasFor declaration on %s points to itself. "
+ "Specify 'annotation' to point to a same-named "
+ "attribute on a meta-annotation.",
"@AliasFor declaration on %s points to itself. " +
"Specify 'annotation' to point to a same-named attribute on a meta-annotation.",
AttributeMethods.describe(attribute)));
}
if (!isCompatibleReturnType(attribute.getReturnType(), target.getReturnType())) {
@ -175,10 +160,10 @@ final class AnnotationTypeMapping {
if (isAliasPair(target) && checkAliasPair) {
AliasFor targetAliasFor = target.getAnnotation(AliasFor.class);
if (targetAliasFor == null) {
throw new AnnotationConfigurationException(
String.format("%s must be declared as an @AliasFor '%s'.",
StringUtils.capitalize(AttributeMethods.describe(target)),
attribute.getName()));
throw new AnnotationConfigurationException(String.format(
"%s must be declared as an @AliasFor '%s'.",
StringUtils.capitalize(AttributeMethods.describe(target)),
attribute.getName()));
}
Method mirror = resolveAliasTarget(target, targetAliasFor, false);
if (mirror != attribute) {
@ -288,10 +273,10 @@ final class AnnotationTypeMapping {
for (int i = 0; i < this.attributes.size(); i++) {
Method attribute = this.attributes.get(i);
AnnotationTypeMapping mapping = this;
while (mapping.depth > 0) {
while (mapping != null && mapping.depth > 0) {
int mapped = mapping.getAttributes().indexOf(attribute.getName());
if (mapped != -1 && (this.annotationValueMappings[i] == -1
|| this.annotationValueSource[i].depth > mapping.depth)) {
if (mapped != -1 && (this.annotationValueMappings[i] == -1 ||
this.annotationValueSource[i].depth > mapping.depth)) {
this.annotationValueMappings[i] = mapped;
this.annotationValueSource[i] = mapping;
}
@ -320,8 +305,7 @@ final class AnnotationTypeMapping {
Method target = resolveAliasTarget(attribute, aliasFor);
throw new AnnotationConfigurationException(String.format(
"@AliasFor declaration on %s declares an alias for %s which is not meta-present.",
AttributeMethods.describe(attribute),
AttributeMethods.describe(target)));
AttributeMethods.describe(attribute), AttributeMethods.describe(target)));
}
}
}
@ -335,14 +319,12 @@ final class AnnotationTypeMapping {
if (firstDefaultValue == null || mirrorDefaultValue == null) {
throw new AnnotationConfigurationException(String.format(
"Misconfigured aliases: %s and %s must declare default values.",
AttributeMethods.describe(firstAttribute),
AttributeMethods.describe(mirrorAttribute)));
AttributeMethods.describe(firstAttribute), AttributeMethods.describe(mirrorAttribute)));
}
if (!ObjectUtils.nullSafeEquals(firstDefaultValue, mirrorDefaultValue)) {
throw new AnnotationConfigurationException(String.format(
"Misconfigured aliases: %s and %s must declare the same default value.",
AttributeMethods.describe(firstAttribute),
AttributeMethods.describe(mirrorAttribute)));
AttributeMethods.describe(firstAttribute), AttributeMethods.describe(mirrorAttribute)));
}
}
}
@ -438,8 +420,7 @@ final class AnnotationTypeMapping {
return null;
}
AnnotationTypeMapping source = this.annotationValueSource[attributeIndex];
return ReflectionUtils.invokeMethod(source.attributes.get(mapped),
source.annotation);
return ReflectionUtils.invokeMethod(source.attributes.get(mapped), source.annotation);
}
/**
@ -453,6 +434,7 @@ final class AnnotationTypeMapping {
*/
boolean isEquivalentToDefaultValue(int attributeIndex, Object value,
BiFunction<Method, Object, Object> valueExtractor) {
Method attribute = this.attributes.get(attributeIndex);
return isEquivalentToDefaultValue(attribute, value, valueExtractor);
}
@ -465,20 +447,22 @@ final class AnnotationTypeMapping {
return this.mirrorSets;
}
private static int[] filledIntArray(int size, int value) {
private static int[] filledIntArray(int size) {
int[] array = new int[size];
Arrays.fill(array, value);
Arrays.fill(array, -1);
return array;
}
private static boolean isEquivalentToDefaultValue(Method attribute, Object value,
BiFunction<Method, Object, Object> valueExtractor) {
return areEquivalent(attribute.getDefaultValue(), value, valueExtractor);
}
private static boolean areEquivalent(@Nullable Object value,
@Nullable Object extractedValue,
private static boolean areEquivalent(@Nullable Object value, @Nullable Object extractedValue,
BiFunction<Method, Object, Object> valueExtractor) {
if (ObjectUtils.nullSafeEquals(value, extractedValue)) {
return true;
}
@ -512,8 +496,8 @@ final class AnnotationTypeMapping {
private static boolean areEquivalent(Annotation value, @Nullable Object extractedValue,
BiFunction<Method, Object, Object> valueExtractor) {
AttributeMethods attributes = AttributeMethods.forAnnotationType(
value.annotationType());
AttributeMethods attributes = AttributeMethods.forAnnotationType(value.annotationType());
for (int i = 0; i < attributes.size(); i++) {
Method attribute = attributes.get(i);
if (!areEquivalent(ReflectionUtils.invokeMethod(attribute, value),
@ -535,13 +519,11 @@ final class AnnotationTypeMapping {
private final MirrorSet[] assigned;
MirrorSets() {
this.assigned = new MirrorSet[attributes.size()];
this.mirrorSets = new MirrorSet[0];
}
void updateFrom(Collection<Method> aliases) {
MirrorSet mirrorSet = null;
int size = 0;
@ -562,8 +544,7 @@ final class AnnotationTypeMapping {
}
if (mirrorSet != null) {
mirrorSet.update();
LinkedHashSet<MirrorSet> unique = new LinkedHashSet<>(
Arrays.asList(this.assigned));
Set<MirrorSet> unique = new LinkedHashSet<>(Arrays.asList(this.assigned));
unique.remove(null);
this.mirrorSets = unique.toArray(new MirrorSet[0]);
}
@ -609,7 +590,6 @@ final class AnnotationTypeMapping {
private final int[] indexes = new int[attributes.size()];
void update() {
this.size = 0;
Arrays.fill(this.indexes, -1);
@ -629,8 +609,8 @@ final class AnnotationTypeMapping {
for (int i = 0; i < this.size; i++) {
Method attribute = attributes.get(this.indexes[i]);
Object value = valueExtractor.apply(attribute, annotation);
boolean isDefaultValue = value == null || isEquivalentToDefaultValue(
attribute, value, valueExtractor);
boolean isDefaultValue = (value == null ||
isEquivalentToDefaultValue(attribute, value, valueExtractor));
if (isDefaultValue || ObjectUtils.nullSafeEquals(lastValue, value)) {
continue;
}
@ -638,8 +618,8 @@ final class AnnotationTypeMapping {
!ObjectUtils.nullSafeEquals(lastValue, value)) {
String on = (source != null) ? " declared on " + source : "";
throw new AnnotationConfigurationException(String.format(
"Different @AliasFor mirror values for annotation [%s]%s, "
+ "attribute '%s' and its alias '%s' are declared with values of [%s] and [%s].",
"Different @AliasFor mirror values for annotation [%s]%s, attribute '%s' " +
"and its alias '%s' are declared with values of [%s] and [%s].",
getAnnotationType().getName(), on,
attributes.get(result).getName(),
attribute.getName(),
@ -664,8 +644,7 @@ final class AnnotationTypeMapping {
int getAttributeIndex(int index) {
return this.indexes[index];
}
}
}
}

View File

@ -118,17 +118,13 @@ abstract class AnnotationsScanner {
switch (searchStrategy) {
case DIRECT:
return processElement(context, source,
processor, classFilter);
return processElement(context, source, processor, classFilter);
case INHERITED_ANNOTATIONS:
return processClassInheritedAnnotations(context, source,
processor, classFilter);
return processClassInheritedAnnotations(context, source, processor, classFilter);
case SUPER_CLASS:
return processClassHierarchy(context, new int[] { 0 }, source,
processor, classFilter, false);
return processClassHierarchy(context, new int[] {0}, source, processor, classFilter, false);
case EXHAUSTIVE:
return processClassHierarchy(context, new int[] { 0 }, source,
processor, classFilter, true);
return processClassHierarchy(context, new int[] {0}, source, processor, classFilter, true);
}
throw new IllegalStateException("Unsupported search strategy " + searchStrategy);
}
@ -405,8 +401,8 @@ abstract class AnnotationsScanner {
AnnotationsProcessor<C, R> processor, @Nullable BiPredicate<C, Class<?>> classFilter) {
R result = processor.doWithAggregate(context, 0);
return (result != null ? result : processor.doWithAnnotations(context, 0, source,
getDeclaredAnnotations(context, source, classFilter, false)));
return (result != null ? result : processor.doWithAnnotations(
context, 0, source, getDeclaredAnnotations(context, source, classFilter, false)));
}
private static <C, R> Annotation[] getDeclaredAnnotations(C context,
@ -426,7 +422,7 @@ abstract class AnnotationsScanner {
static <A extends Annotation> A getDeclaredAnnotation(AnnotatedElement source, Class<A> annotationType) {
Annotation[] annotations = getDeclaredAnnotations(source, false);
for (Annotation annotation : annotations) {
if (annotation != null && annotationType.equals(annotation.annotationType())) {
if (annotation != null && annotationType == annotation.annotationType()) {
return (A) annotation;
}
}
@ -500,9 +496,12 @@ abstract class AnnotationsScanner {
else {
return false;
}
if (type == Ordered.class) {
return true;
}
String name = type.getName();
return (type == Ordered.class ||
name.startsWith("java") ||
return (name.startsWith("java") ||
name.startsWith("org.springframework.lang.") ||
name.startsWith("org.springframework.util.") ||
(name.startsWith("com.sun") && !name.contains("Proxy")));

View File

@ -111,8 +111,8 @@ public abstract class RepeatableContainers {
* {@code repeatable}.
* @return a {@link RepeatableContainers} instance
*/
public static RepeatableContainers of(Class<? extends Annotation> repeatable,
@Nullable Class<? extends Annotation> container) {
public static RepeatableContainers of(
Class<? extends Annotation> repeatable, @Nullable Class<? extends Annotation> container) {
return new ExplicitRepeatableContainer(null, repeatable, container);
}
@ -133,13 +133,11 @@ public abstract class RepeatableContainers {
*/
private static class StandardRepeatableContainers extends RepeatableContainers {
private static final Map<Class<? extends Annotation>, Object> cache =
new ConcurrentReferenceHashMap<>();
private static final Map<Class<? extends Annotation>, Object> cache = new ConcurrentReferenceHashMap<>();
private static final Object NONE = new Object();
private static StandardRepeatableContainers INSTANCE =
new StandardRepeatableContainers();
private static StandardRepeatableContainers INSTANCE = new StandardRepeatableContainers();
StandardRepeatableContainers() {
super(null);
@ -156,17 +154,13 @@ public abstract class RepeatableContainers {
}
@Nullable
private static Method getRepeatedAnnotationsMethod(
Class<? extends Annotation> annotationType) {
private static Method getRepeatedAnnotationsMethod(Class<? extends Annotation> annotationType) {
Object result = cache.computeIfAbsent(annotationType,
StandardRepeatableContainers::computeRepeatedAnnotationsMethod);
return result != NONE ? (Method) result : null;
return (result != NONE ? (Method) result : null);
}
private static Object computeRepeatedAnnotationsMethod(
Class<? extends Annotation> annotationType) {
private static Object computeRepeatedAnnotationsMethod(Class<? extends Annotation> annotationType) {
AttributeMethods methods = AttributeMethods.forAnnotationType(annotationType);
if (methods.isOnlyValueAttribute()) {
Method method = methods.get("value");
@ -176,15 +170,14 @@ public abstract class RepeatableContainers {
Class<?> returnType = method.getReturnType();
if (returnType.isArray()) {
Class<?> componentType = returnType.getComponentType();
if (Annotation.class.isAssignableFrom(componentType)
&& componentType.isAnnotationPresent(Repeatable.class)) {
if (Annotation.class.isAssignableFrom(componentType) &&
componentType.isAnnotationPresent(Repeatable.class)) {
return method;
}
}
}
return NONE;
}
}

View File

@ -248,9 +248,8 @@ final class TypeMappedAnnotations implements MergedAnnotations {
return null;
}
static MergedAnnotations from(@Nullable AnnotatedElement element,
SearchStrategy searchStrategy, RepeatableContainers repeatableContainers,
AnnotationFilter annotationFilter) {
static MergedAnnotations from(@Nullable AnnotatedElement element, SearchStrategy searchStrategy,
RepeatableContainers repeatableContainers, AnnotationFilter annotationFilter) {
if (element == null || AnnotationsScanner.isKnownEmpty(element, searchStrategy, annotationFilter)) {
return NONE;
@ -324,11 +323,11 @@ final class TypeMappedAnnotations implements MergedAnnotations {
if (type == requiredType || type.getName().equals(requiredType)) {
return Boolean.TRUE;
}
Annotation[] repeatedAnnotations = this.repeatableContainers
.findRepeatedAnnotations(annotation);
Annotation[] repeatedAnnotations =
this.repeatableContainers.findRepeatedAnnotations(annotation);
if (repeatedAnnotations != null) {
Boolean result = doWithAnnotations(requiredType, aggregateIndex,
source, repeatedAnnotations);
Boolean result = doWithAnnotations(
requiredType, aggregateIndex, source, repeatedAnnotations);
if (result != null) {
return result;
}
@ -402,8 +401,7 @@ final class TypeMappedAnnotations implements MergedAnnotations {
@Nullable Object source, Annotation[] annotations) {
for (Annotation annotation : annotations) {
if (annotation != null &&
!annotationFilter.matches(annotation)) {
if (annotation != null && !annotationFilter.matches(annotation)) {
MergedAnnotation<A> result = process(type, aggregateIndex, source, annotation);
if (result != null) {
return result;

View File

@ -68,8 +68,7 @@ public class AnnotationIntrospectionFailureTests {
assertThat(AnnotatedElementUtils.getMergedAnnotationAttributes(
withExampleMetaAnnotation, exampleAnnotationClass)).isNull();
assertThat(AnnotatedElementUtils.getMergedAnnotationAttributes(
withExampleMetaAnnotation,
exampleMetaAnnotationClass)).isNull();
withExampleMetaAnnotation, exampleMetaAnnotationClass)).isNull();
assertThat(AnnotatedElementUtils.hasAnnotation(withExampleMetaAnnotation,
exampleAnnotationClass)).isFalse();
assertThat(AnnotatedElementUtils.hasAnnotation(withExampleMetaAnnotation,
@ -97,12 +96,10 @@ public class AnnotationIntrospectionFailureTests {
static class FilteringClassLoader extends OverridingClassLoader {
FilteringClassLoader(ClassLoader parent) {
super(parent);
}
@Override
protected boolean isEligibleForOverriding(String className) {
return className.startsWith(
@ -110,36 +107,31 @@ public class AnnotationIntrospectionFailureTests {
}
@Override
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException {
if (name.startsWith(AnnotationIntrospectionFailureTests.class.getName())
&& name.contains("Filtered")) {
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
if (name.startsWith(AnnotationIntrospectionFailureTests.class.getName()) &&
name.contains("Filtered")) {
throw new ClassNotFoundException(name);
}
return super.loadClass(name, resolve);
}
}
static class FilteredType {
}
@Retention(RetentionPolicy.RUNTIME)
static @interface ExampleAnnotation {
@interface ExampleAnnotation {
Class<?> value() default Void.class;
}
@ExampleAnnotation(FilteredType.class)
static class WithExampleAnnotation {
}
@Retention(RetentionPolicy.RUNTIME)
@ExampleAnnotation
static @interface ExampleMetaAnnotation {
@interface ExampleMetaAnnotation {
@AliasFor(annotation = ExampleAnnotation.class, attribute = "value")
Class<?> example1() default Void.class;
@ -151,7 +143,6 @@ public class AnnotationIntrospectionFailureTests {
@ExampleMetaAnnotation(example1 = FilteredType.class)
static class WithExampleMetaAnnotation {
}
}