Merge branch '5.3.x'
# Conflicts: # spring-core/src/main/java/org/springframework/core/annotation/TypeMappedAnnotation.java
This commit is contained in:
commit
730d6c95fc
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2019 the original author or authors.
|
* Copyright 2002-2022 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -207,7 +207,7 @@ abstract class AbstractMergedAnnotation<A extends Annotation> implements MergedA
|
||||||
}
|
}
|
||||||
A synthesized = this.synthesizedAnnotation;
|
A synthesized = this.synthesizedAnnotation;
|
||||||
if (synthesized == null) {
|
if (synthesized == null) {
|
||||||
synthesized = createSynthesized();
|
synthesized = createSynthesizedAnnotation();
|
||||||
this.synthesizedAnnotation = synthesized;
|
this.synthesizedAnnotation = synthesized;
|
||||||
}
|
}
|
||||||
return synthesized;
|
return synthesized;
|
||||||
|
|
@ -237,7 +237,11 @@ abstract class AbstractMergedAnnotation<A extends Annotation> implements MergedA
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory method used to create the synthesized annotation.
|
* Factory method used to create the synthesized annotation.
|
||||||
|
* <p>If the source is an annotation that is not <em>synthesizable</em>, it
|
||||||
|
* will be returned unmodified.
|
||||||
|
* <p>Consult the documentation for {@link MergedAnnotation#synthesize()}
|
||||||
|
* for an explanation of what is considered synthesizable.
|
||||||
*/
|
*/
|
||||||
protected abstract A createSynthesized();
|
protected abstract A createSynthesizedAnnotation();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -19,7 +19,6 @@ package org.springframework.core.annotation;
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.annotation.Inherited;
|
import java.lang.annotation.Inherited;
|
||||||
import java.lang.reflect.AnnotatedElement;
|
import java.lang.reflect.AnnotatedElement;
|
||||||
import java.lang.reflect.Proxy;
|
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
@ -481,12 +480,15 @@ public interface MergedAnnotation<A extends Annotation> {
|
||||||
/**
|
/**
|
||||||
* Create a type-safe synthesized version of this merged annotation that can
|
* Create a type-safe synthesized version of this merged annotation that can
|
||||||
* be used directly in code.
|
* be used directly in code.
|
||||||
* <p>The result is synthesized using a JDK {@link Proxy} and as a result may
|
* <p>The result is synthesized using a JDK {@link java.lang.reflect.Proxy Proxy}
|
||||||
* incur a computational cost when first invoked.
|
* and as a result may incur a computational cost when first invoked.
|
||||||
|
* <p>If this merged annotation was created {@linkplain #of(AnnotatedElement, Class, Map)
|
||||||
|
* from} a map of annotation attributes or default attribute values, those
|
||||||
|
* attributes will always be synthesized into an annotation instance.
|
||||||
* <p>If this merged annotation was created {@linkplain #from(Annotation) from}
|
* <p>If this merged annotation was created {@linkplain #from(Annotation) from}
|
||||||
* an annotation instance, that annotation will be returned unmodified if it is
|
* an annotation instance, that annotation will be returned unmodified if it is
|
||||||
* not <em>synthesizable</em>. An annotation is considered synthesizable if
|
* not <em>synthesizable</em>. An annotation is considered synthesizable if
|
||||||
* one of the following is true.
|
* it has not already been synthesized and one of the following is true.
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>The annotation declares attributes annotated with {@link AliasFor @AliasFor}.</li>
|
* <li>The annotation declares attributes annotated with {@link AliasFor @AliasFor}.</li>
|
||||||
* <li>The annotation is a composed annotation that relies on convention-based
|
* <li>The annotation is a composed annotation that relies on convention-based
|
||||||
|
|
@ -503,8 +505,8 @@ public interface MergedAnnotation<A extends Annotation> {
|
||||||
/**
|
/**
|
||||||
* Optionally create a type-safe synthesized version of this annotation based
|
* Optionally create a type-safe synthesized version of this annotation based
|
||||||
* on a condition predicate.
|
* on a condition predicate.
|
||||||
* <p>The result is synthesized using a JDK {@link Proxy} and as a result may
|
* <p>The result is synthesized using a JDK {@link java.lang.reflect.Proxy Proxy}
|
||||||
* incur a computational cost when first invoked.
|
* and as a result may incur a computational cost when first invoked.
|
||||||
* <p>Consult the documentation for {@link #synthesize()} for an explanation
|
* <p>Consult the documentation for {@link #synthesize()} for an explanation
|
||||||
* of what is considered synthesizable.
|
* of what is considered synthesizable.
|
||||||
* @param condition the test to determine if the annotation can be synthesized
|
* @param condition the test to determine if the annotation can be synthesized
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,7 @@ final class MissingMergedAnnotation<A extends Annotation> extends AbstractMerged
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected A createSynthesized() {
|
protected A createSynthesizedAnnotation() {
|
||||||
throw new NoSuchElementException("Unable to synthesize missing annotation");
|
throw new NoSuchElementException("Unable to synthesize missing annotation");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2021 the original author or authors.
|
* Copyright 2002-2022 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -321,19 +321,37 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected A createSynthesized() {
|
protected A createSynthesizedAnnotation() {
|
||||||
if (getType().isInstance(this.rootAttributes) && !isSynthesizable()) {
|
// Check root annotation
|
||||||
|
if (isTargetAnnotation(this.rootAttributes) && isNotSynthesizable((Annotation) this.rootAttributes)) {
|
||||||
return (A) this.rootAttributes;
|
return (A) this.rootAttributes;
|
||||||
}
|
}
|
||||||
|
// Check meta-annotation
|
||||||
|
else if (isTargetAnnotation(this.mapping.getAnnotation()) && isNotSynthesizable(this.mapping.getAnnotation())) {
|
||||||
|
return (A) this.mapping.getAnnotation();
|
||||||
|
}
|
||||||
return SynthesizedMergedAnnotationInvocationHandler.createProxy(this, getType());
|
return SynthesizedMergedAnnotationInvocationHandler.createProxy(this, getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isSynthesizable() {
|
/**
|
||||||
// Already synthesized?
|
* Determine if the supplied object is an annotation of the required
|
||||||
if (this.rootAttributes instanceof SynthesizedAnnotation) {
|
* {@linkplain #getType() type}.
|
||||||
return false;
|
* @param obj the object to check
|
||||||
|
* @since 5.3.22
|
||||||
|
*/
|
||||||
|
private boolean isTargetAnnotation(@Nullable Object obj) {
|
||||||
|
return getType().isInstance(obj);
|
||||||
}
|
}
|
||||||
return this.mapping.isSynthesizable();
|
|
||||||
|
/**
|
||||||
|
* Determine if the supplied annotation has already been synthesized or if the
|
||||||
|
* mapped annotation is not {@linkplain AnnotationTypeMapping#isSynthesizable()
|
||||||
|
* synthesizable} in general.
|
||||||
|
* @param annotation the annotation to check
|
||||||
|
* @since 5.3.22
|
||||||
|
*/
|
||||||
|
private boolean isNotSynthesizable(Annotation annotation) {
|
||||||
|
return (annotation instanceof SynthesizedAnnotation || !this.mapping.isSynthesizable());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -1539,6 +1539,17 @@ class MergedAnnotationsTests {
|
||||||
assertThat(generatedValue).isSameAs(synthesizedGeneratedValue);
|
assertThat(generatedValue).isSameAs(synthesizedGeneratedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void synthesizeShouldNotSynthesizeNonsynthesizableAnnotationsWhenUsingMergedAnnotationsFromApi() {
|
||||||
|
MergedAnnotations mergedAnnotations = MergedAnnotations.from(SecurityConfig.class);
|
||||||
|
|
||||||
|
EnableWebSecurity enableWebSecurity = mergedAnnotations.get(EnableWebSecurity.class).synthesize();
|
||||||
|
assertThat(enableWebSecurity).isNotInstanceOf(SynthesizedAnnotation.class);
|
||||||
|
|
||||||
|
EnableGlobalAuthentication enableGlobalAuthentication = mergedAnnotations.get(EnableGlobalAuthentication.class).synthesize();
|
||||||
|
assertThat(enableGlobalAuthentication).isNotInstanceOf(SynthesizedAnnotation.class);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If an attempt is made to synthesize an annotation from an annotation instance
|
* If an attempt is made to synthesize an annotation from an annotation instance
|
||||||
* that has already been synthesized, the original synthesized annotation should
|
* that has already been synthesized, the original synthesized annotation should
|
||||||
|
|
@ -3216,6 +3227,25 @@ class MergedAnnotationsTests {
|
||||||
return 42L;
|
return 42L;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mimics org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication
|
||||||
|
*/
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
@interface EnableGlobalAuthentication {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mimics org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
|
||||||
|
*/
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
@EnableGlobalAuthentication
|
||||||
|
@interface EnableWebSecurity {
|
||||||
|
}
|
||||||
|
|
||||||
|
@EnableWebSecurity
|
||||||
|
static class SecurityConfig {
|
||||||
|
}
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@interface TestConfiguration {
|
@interface TestConfiguration {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,8 +61,8 @@ class BootstrapUtilsTests {
|
||||||
@Test
|
@Test
|
||||||
void resolveTestContextBootstrapperWithEmptyBootstrapWithAnnotation() {
|
void resolveTestContextBootstrapperWithEmptyBootstrapWithAnnotation() {
|
||||||
BootstrapContext bootstrapContext = BootstrapTestUtils.buildBootstrapContext(EmptyBootstrapWithAnnotationClass.class, delegate);
|
BootstrapContext bootstrapContext = BootstrapTestUtils.buildBootstrapContext(EmptyBootstrapWithAnnotationClass.class, delegate);
|
||||||
assertThatIllegalStateException().isThrownBy(() ->
|
assertThatIllegalStateException()
|
||||||
resolveTestContextBootstrapper(bootstrapContext))
|
.isThrownBy(() -> resolveTestContextBootstrapper(bootstrapContext))
|
||||||
.withMessageContaining("Specify @BootstrapWith's 'value' attribute");
|
.withMessageContaining("Specify @BootstrapWith's 'value' attribute");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -70,11 +70,11 @@ class BootstrapUtilsTests {
|
||||||
void resolveTestContextBootstrapperWithDoubleMetaBootstrapWithAnnotations() {
|
void resolveTestContextBootstrapperWithDoubleMetaBootstrapWithAnnotations() {
|
||||||
BootstrapContext bootstrapContext = BootstrapTestUtils.buildBootstrapContext(
|
BootstrapContext bootstrapContext = BootstrapTestUtils.buildBootstrapContext(
|
||||||
DoubleMetaAnnotatedBootstrapWithAnnotationClass.class, delegate);
|
DoubleMetaAnnotatedBootstrapWithAnnotationClass.class, delegate);
|
||||||
assertThatIllegalStateException().isThrownBy(() ->
|
assertThatIllegalStateException()
|
||||||
resolveTestContextBootstrapper(bootstrapContext))
|
.isThrownBy(() -> resolveTestContextBootstrapper(bootstrapContext))
|
||||||
.withMessageContaining("Configuration error: found multiple declarations of @BootstrapWith")
|
.withMessageContaining("Configuration error: found multiple declarations of @BootstrapWith")
|
||||||
.withMessageContaining(FooBootstrapper.class.getCanonicalName())
|
.withMessageContaining(FooBootstrapper.class.getSimpleName())
|
||||||
.withMessageContaining(BarBootstrapper.class.getCanonicalName());
|
.withMessageContaining(BarBootstrapper.class.getSimpleName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue