Ensure AnnotationTypeMapping properly tracks convention-based mappings

AnnotationTypeMapping.addConventionMappings() sometimes adds
convention-based mappings that it should not.

For example, in certain circumstances an explicit annotation attribute
override configured via @AliasFor can be incorrectly mapped as
convention-based.

Although this does not appear to cause negative side effects (other
than unnecessary processing), this is technically a bug, and this
commit address this issue.

Closes gh-28773
This commit is contained in:
Sam Brannen 2022-07-07 17:33:27 +02:00
parent 5397d4721b
commit 81acbe7e2f
1 changed files with 23 additions and 2 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2022 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.
@ -272,7 +272,7 @@ final class AnnotationTypeMapping {
for (int i = 0; i < mappings.length; i++) {
String name = this.attributes.get(i).getName();
int mapped = rootAttributes.indexOf(name);
if (!MergedAnnotation.VALUE.equals(name) && mapped != -1) {
if (!MergedAnnotation.VALUE.equals(name) && mapped != -1 && !isExplicitAttributeOverride(name)) {
mappings[i] = mapped;
MirrorSet mirrors = getMirrorSets().getAssigned(i);
if (mirrors != null) {
@ -284,6 +284,27 @@ final class AnnotationTypeMapping {
}
}
/**
* Determine if the given annotation attribute in the {@linkplain #getRoot()
* root annotation} is an explicit annotation attribute override for an
* attribute in a meta-annotation, explicit in the sense that the override
* is declared via {@link AliasFor @AliasFor}.
* <p>If the named attribute does not exist in the root annotation, this
* method returns {@code false}.
* @param name the name of the annotation attribute to check
* @since 6.0
*/
private boolean isExplicitAttributeOverride(String name) {
Method attribute = this.root.getAttributes().get(name);
if (attribute != null) {
AliasFor aliasFor = AnnotationsScanner.getDeclaredAnnotation(attribute, AliasFor.class);
return ((aliasFor != null) &&
(aliasFor.annotation() != Annotation.class) &&
(aliasFor.annotation() != this.root.annotationType));
}
return false;
}
private void addConventionAnnotationValues() {
for (int i = 0; i < this.attributes.size(); i++) {
Method attribute = this.attributes.get(i);