AnnotationUtils.synthesizeAnnotation explicitly checks whether SynthesizedAnnotation is exposable

Issue: SPR-13696
This commit is contained in:
Juergen Hoeller 2015-12-07 17:36:14 +01:00
parent 40cff5e340
commit d0814703c4
2 changed files with 63 additions and 27 deletions

View File

@ -514,7 +514,7 @@ public abstract class AnnotationUtils {
try {
Annotation[] anns = annotatedElement.getDeclaredAnnotations();
for (Annotation ann : anns) {
if (ann.annotationType().equals(annotationType)) {
if (ann.annotationType() == annotationType) {
return (A) ann;
}
}
@ -703,7 +703,7 @@ public abstract class AnnotationUtils {
try {
Annotation[] anns = clazz.getDeclaredAnnotations();
for (Annotation ann : anns) {
if (ann.annotationType().equals(annotationType)) {
if (ann.annotationType() == annotationType) {
return (A) ann;
}
}
@ -828,7 +828,7 @@ public abstract class AnnotationUtils {
Assert.notNull(clazz, "Class must not be null");
try {
for (Annotation ann : clazz.getDeclaredAnnotations()) {
if (ann.annotationType().equals(annotationType)) {
if (ann.annotationType() == annotationType) {
return true;
}
}
@ -1360,7 +1360,8 @@ public abstract class AnnotationUtils {
if (annotation == null) {
return null;
}
if (annotation instanceof SynthesizedAnnotation) {
if (annotation instanceof SynthesizedAnnotation || (Proxy.isProxyClass(annotation.getClass()) &&
Proxy.getInvocationHandler(annotation) instanceof SynthesizedAnnotationInvocationHandler)) {
return annotation;
}
@ -1372,8 +1373,9 @@ public abstract class AnnotationUtils {
DefaultAnnotationAttributeExtractor attributeExtractor =
new DefaultAnnotationAttributeExtractor(annotation, annotatedElement);
InvocationHandler handler = new SynthesizedAnnotationInvocationHandler(attributeExtractor);
return (A) Proxy.newProxyInstance(annotation.getClass().getClassLoader(),
new Class<?>[] {(Class<A>) annotationType, SynthesizedAnnotation.class}, handler);
Class<?>[] exposedInterfaces = (canExposeSynthesizedMarker(annotationType) ?
new Class<?>[] {annotationType, SynthesizedAnnotation.class} : new Class<?>[] {annotationType});
return (A) Proxy.newProxyInstance(annotation.getClass().getClassLoader(), exposedInterfaces, handler);
}
/**
@ -1418,8 +1420,9 @@ public abstract class AnnotationUtils {
MapAnnotationAttributeExtractor attributeExtractor =
new MapAnnotationAttributeExtractor(attributes, annotationType, annotatedElement);
InvocationHandler handler = new SynthesizedAnnotationInvocationHandler(attributeExtractor);
return (A) Proxy.newProxyInstance(annotationType.getClassLoader(),
new Class<?>[] {annotationType, SynthesizedAnnotation.class}, handler);
Class<?>[] exposedInterfaces = (canExposeSynthesizedMarker(annotationType) ?
new Class<?>[] {annotationType, SynthesizedAnnotation.class} : new Class<?>[] {annotationType});
return (A) Proxy.newProxyInstance(annotationType.getClassLoader(), exposedInterfaces, handler);
}
/**
@ -1539,10 +1542,23 @@ public abstract class AnnotationUtils {
}
attributeAliasesCache.put(annotationType, map);
return map;
}
/**
* Check whether we can expose our {@link SynthesizedAnnotation} marker for the given annotation type.
* @param annotationType the annotation type that we are about to create a synthesized proxy for
*/
private static boolean canExposeSynthesizedMarker(Class<? extends Annotation> annotationType) {
try {
return (Class.forName(SynthesizedAnnotation.class.getName(), false, annotationType.getClassLoader()) ==
SynthesizedAnnotation.class);
}
catch (ClassNotFoundException ex) {
return false;
}
}
/**
* Determine if annotations of the supplied {@code annotationType} are
* <em>synthesizable</em> (i.e., in need of being wrapped in a dynamic
@ -1629,7 +1645,7 @@ public abstract class AnnotationUtils {
static String getAttributeOverrideName(Method attribute, Class<? extends Annotation> metaAnnotationType) {
Assert.notNull(attribute, "attribute must not be null");
Assert.notNull(metaAnnotationType, "metaAnnotationType must not be null");
Assert.isTrue(!Annotation.class.equals(metaAnnotationType),
Assert.isTrue(Annotation.class != metaAnnotationType,
"metaAnnotationType must not be [java.lang.annotation.Annotation]");
AliasDescriptor descriptor = AliasDescriptor.from(attribute);
@ -1931,7 +1947,7 @@ public abstract class AnnotationUtils {
this.sourceAnnotationType = (Class<? extends Annotation>) declaringClass;
this.sourceAttributeName = this.sourceAttribute.getName();
this.aliasedAnnotationType = (Annotation.class.equals(aliasFor.annotation()) ?
this.aliasedAnnotationType = (Annotation.class == aliasFor.annotation() ?
this.sourceAnnotationType : aliasFor.annotation());
this.aliasedAttributeName = getAliasedAttributeName(aliasFor, this.sourceAttribute);
try {
@ -1945,7 +1961,7 @@ public abstract class AnnotationUtils {
throw new AnnotationConfigurationException(msg, ex);
}
this.isAliasPair = this.sourceAnnotationType.equals(this.aliasedAnnotationType);
this.isAliasPair = (this.sourceAnnotationType == this.aliasedAnnotationType);
}
private void validate() {
@ -1979,7 +1995,7 @@ public abstract class AnnotationUtils {
Class<?> returnType = this.sourceAttribute.getReturnType();
Class<?> aliasedReturnType = this.aliasedAttribute.getReturnType();
if (!returnType.equals(aliasedReturnType)) {
if (returnType != aliasedReturnType) {
String msg = String.format("Misconfigured aliases: attribute [%s] in annotation [%s] " +
"and attribute [%s] in annotation [%s] must declare the same return type.",
this.sourceAttributeName, this.sourceAnnotationType.getName(), this.aliasedAttributeName,
@ -2030,7 +2046,7 @@ public abstract class AnnotationUtils {
* @see #isAliasFor
*/
private boolean isOverrideFor(Class<? extends Annotation> metaAnnotationType) {
return this.aliasedAnnotationType.equals(metaAnnotationType);
return (this.aliasedAnnotationType == metaAnnotationType);
}
/**
@ -2087,7 +2103,7 @@ public abstract class AnnotationUtils {
public String getAttributeOverrideName(Class<? extends Annotation> metaAnnotationType) {
Assert.notNull(metaAnnotationType, "metaAnnotationType must not be null");
Assert.isTrue(!Annotation.class.equals(metaAnnotationType),
Assert.isTrue(Annotation.class != metaAnnotationType,
"metaAnnotationType must not be [java.lang.annotation.Annotation]");
// Search the attribute override hierarchy, starting with the current attribute

View File

@ -23,9 +23,12 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.List;
import java.util.Set;
import javax.annotation.Resource;
import org.junit.Ignore;
import org.junit.Rule;
@ -632,7 +635,20 @@ public class AnnotatedElementUtilsTests {
assertArrayEquals("locations for " + element, EMPTY, contextConfig.locations());
// 'value' in @SpringAppConfig should not override 'value' in @ContextConfig
assertArrayEquals("value for " + element, EMPTY, contextConfig.value());
assertArrayEquals("classes for " + element, new Class<?>[] { Number.class }, contextConfig.classes());
assertArrayEquals("classes for " + element, new Class<?>[] {Number.class}, contextConfig.classes());
}
@Test
public void javaLangAnnotationTypeViaFindMergedAnnotation() throws Exception {
Constructor<?> deprecatedCtor = Date.class.getConstructor(String.class);
assertEquals(deprecatedCtor.getAnnotation(Deprecated.class), findMergedAnnotation(deprecatedCtor, Deprecated.class));
assertEquals(Date.class.getAnnotation(Deprecated.class), findMergedAnnotation(Date.class, Deprecated.class));
}
@Test
public void javaxAnnotationTypeViaFindMergedAnnotation() throws Exception {
assertEquals(ResourceHolder.class.getAnnotation(Resource.class), findMergedAnnotation(ResourceHolder.class, Resource.class));
assertEquals(SpringAppConfigClass.class.getAnnotation(Resource.class), findMergedAnnotation(SpringAppConfigClass.class, Resource.class));
}
@ -685,7 +701,7 @@ public class AnnotatedElementUtilsTests {
// -------------------------------------------------------------------------
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Target({ElementType.TYPE, ElementType.METHOD})
@Inherited
@interface Transactional {
@ -697,7 +713,7 @@ public class AnnotatedElementUtilsTests {
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Target({ElementType.TYPE, ElementType.METHOD})
@Inherited
@interface AliasedTransactional {
@ -849,7 +865,7 @@ public class AnnotatedElementUtilsTests {
String[] value() default {};
}
@ImplicitAliasesContextConfig(xmlFiles = { "A.xml", "B.xml" })
@ImplicitAliasesContextConfig(xmlFiles = {"A.xml", "B.xml"})
@Retention(RetentionPolicy.RUNTIME)
@interface ComposedImplicitAliasesContextConfig {
}
@ -938,7 +954,7 @@ public class AnnotatedElementUtilsTests {
String pattern();
}
@ComponentScan(excludeFilters = { @Filter(pattern = "*Test"), @Filter(pattern = "*Tests") })
@ComponentScan(excludeFilters = {@Filter(pattern = "*Test"), @Filter(pattern = "*Tests")})
@Retention(RetentionPolicy.RUNTIME)
@interface TestComponentScan {
@ -1037,7 +1053,7 @@ public class AnnotatedElementUtilsTests {
}
}
public static interface GenericParameter<T> {
public interface GenericParameter<T> {
T getFor(Class<T> cls);
}
@ -1057,23 +1073,23 @@ public class AnnotatedElementUtilsTests {
}
@Transactional
public static interface InheritedAnnotationInterface {
public interface InheritedAnnotationInterface {
}
public static interface SubInheritedAnnotationInterface extends InheritedAnnotationInterface {
public interface SubInheritedAnnotationInterface extends InheritedAnnotationInterface {
}
public static interface SubSubInheritedAnnotationInterface extends SubInheritedAnnotationInterface {
public interface SubSubInheritedAnnotationInterface extends SubInheritedAnnotationInterface {
}
@Order
public static interface NonInheritedAnnotationInterface {
public interface NonInheritedAnnotationInterface {
}
public static interface SubNonInheritedAnnotationInterface extends NonInheritedAnnotationInterface {
public interface SubNonInheritedAnnotationInterface extends NonInheritedAnnotationInterface {
}
public static interface SubSubNonInheritedAnnotationInterface extends SubNonInheritedAnnotationInterface {
public interface SubSubNonInheritedAnnotationInterface extends SubNonInheritedAnnotationInterface {
}
@ConventionBasedComposedContextConfig(locations = "explicitDeclaration")
@ -1144,4 +1160,8 @@ public class AnnotatedElementUtilsTests {
static class SpringAppConfigClass {
}
@Resource(name = "x")
static class ResourceHolder {
}
}