From 81acbe7e2f2e2fc7afd83f9759e6ad8470766de1 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Thu, 7 Jul 2022 17:33:27 +0200 Subject: [PATCH] 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 --- .../annotation/AnnotationTypeMapping.java | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationTypeMapping.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationTypeMapping.java index 50fbc8fda3..35970f018e 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationTypeMapping.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationTypeMapping.java @@ -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}. + *

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);