Omit deprecation warning for Bean Validation constraint annotations

Prior to this commit, AnnotationTypeMapping logged a warning for the use
of convention-based annotation attribute overrides in composed Bean
Validation constraint annotations, even though those attribute overrides
are not related to Spring.

For example, Hibernate's @URL constraint annotation is meta-annotated
with Bean Validation's @Pattern constraint annotation, and we should not
log a warning in such scenarios.

This commit addresses that by not logging a warning if convention-based
annotation attribute overrides are detected for a composed @Constraint
annotation.

Closes gh-29206
This commit is contained in:
Sam Brannen
2022-10-17 19:39:02 +02:00
parent 0e861af050
commit 4d44aaf81b
2 changed files with 73 additions and 5 deletions

View File

@@ -0,0 +1,52 @@
/*
* 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.validation.beanvalidation;
import java.lang.reflect.Method;
import org.hibernate.validator.constraints.URL;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.springframework.core.annotation.MergedAnnotations;
/**
* Smoke tests specific to the combination of {@link MergedAnnotations}
* and Bean Validation constraint annotations.
*
* @author Sam Brannen
* @since 6.0
*/
class BeanValidationMergedAnnotationsTests {
@Disabled("This test should only be run manually to inspect log messages")
@Test
@URL
void constraintAnnotationOnMethod() throws Exception {
// If the issue raised in gh-29206 had not been addressed, we would see
// a log message similar to the following.
// 19:07:33.848 [main] WARN o.s.c.a.AnnotationTypeMapping - Support for
// convention-based annotation attribute overrides is deprecated and will
// be removed in Spring Framework 6.1. Please annotate the following attributes
// in @org.hibernate.validator.constraints.URL with appropriate @AliasFor
// declarations: [regexp, payload, flags, groups, message]
Method method = getClass().getDeclaredMethod("constraintAnnotationOnMethod");
MergedAnnotations mergedAnnotations = MergedAnnotations.from(method);
mergedAnnotations.get(URL.class);
}
}

View File

@@ -29,6 +29,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -52,9 +53,15 @@ final class AnnotationTypeMapping {
private static final Log logger = LogFactory.getLog(AnnotationTypeMapping.class);
private static final Predicate<? super Annotation> isBeanValidationConstraint = annotation ->
annotation.annotationType().getName().equals("jakarta.validation.Constraint");
/**
* Set of fully qualified class names for annotations which we have already
* checked for use of convention-based annotation attribute overrides.
* Set used to track which convention-based annotation attribute overrides
* have already been checked. Each key is the combination of the fully
* qualified class names of a composed annotation and a meta-annotation
* that it is either present or meta-present on the composed annotation,
* separated by a dash.
* @since 6.0
* @see #addConventionMappings()
*/
@@ -299,9 +306,18 @@ final class AnnotationTypeMapping {
}
}
String rootAnnotationTypeName = this.root.annotationType.getName();
// We want to avoid duplicate log warnings as much as possible, without full synchronization.
if (conventionBasedOverrideCheckCache.add(rootAnnotationTypeName) &&
!conventionMappedAttributes.isEmpty() && logger.isWarnEnabled()) {
String cacheKey = rootAnnotationTypeName + '-' + this.annotationType.getName();
// We want to avoid duplicate log warnings as much as possible, without full synchronization,
// and we intentionally invoke add() before checking if any convention-based overrides were
// actually encountered in order to ensure that we add a "tracked" entry for the current cache
// key in any case.
// In addition, we do NOT want to log warnings for custom Java Bean Validation constraint
// annotations that are meta-annotated with other constraint annotations -- for example,
// @org.hibernate.validator.constraints.URL which overrides attributes in
// @jakarta.validation.constraints.Pattern.
if (conventionBasedOverrideCheckCache.add(cacheKey) && !conventionMappedAttributes.isEmpty() &&
Arrays.stream(this.annotationType.getAnnotations()).noneMatch(isBeanValidationConstraint) &&
logger.isWarnEnabled()) {
logger.warn("""
Support for convention-based annotation attribute overrides is deprecated \
and will be removed in Spring Framework 6.1. Please annotate the following \