提交 b830d736 编写于 作者: S Sam Brannen

Support non-public anno. attr. values in AnnoUtils

Prior to this commit, the getValue(Annotation, String) method in
AnnotationUtils failed to retrieve the value of the desired annotation
attribute if the annotation itself was not public -- for example if the
annotation was declared as package private.

This commit addresses this issue by ensuring that getValue(Annotation,
String) uses reflection to make the desired annotation attribute method
accessible before attempting to invoke it to retrieve the value.

Issue: SPR-11104
上级 45afd4fb
......@@ -31,6 +31,7 @@ import java.util.WeakHashMap;
import org.springframework.core.BridgeMethodResolver;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
/**
* General utility methods for working with annotations, handling bridge methods (which the compiler
......@@ -525,6 +526,7 @@ public abstract class AnnotationUtils {
public static Object getValue(Annotation annotation, String attributeName) {
try {
Method method = annotation.annotationType().getDeclaredMethod(attributeName, new Class[0]);
ReflectionUtils.makeAccessible(method);
return method.invoke(annotation);
}
catch (Exception ex) {
......@@ -585,7 +587,6 @@ public abstract class AnnotationUtils {
private static class AnnotationCollector<A extends Annotation> {
private final Class<? extends Annotation> containerAnnotationType;
private final Class<A> annotationType;
......@@ -628,6 +629,7 @@ public abstract class AnnotationUtils {
private A[] getValue(Annotation annotation) {
try {
Method method = annotation.annotationType().getDeclaredMethod("value");
ReflectionUtils.makeAccessible(method);
return (A[]) method.invoke(annotation);
}
catch (Exception ex) {
......
......@@ -29,10 +29,10 @@ import java.util.Set;
import org.junit.Test;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.subpackage.NonPublicAnnotatedClass;
import org.springframework.stereotype.Component;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.springframework.core.annotation.AnnotationUtils.*;
......@@ -46,7 +46,7 @@ import static org.springframework.core.annotation.AnnotationUtils.*;
public class AnnotationUtilsTests {
@Test
public void testFindMethodAnnotationOnLeaf() throws SecurityException, NoSuchMethodException {
public void findMethodAnnotationOnLeaf() throws Exception {
Method m = Leaf.class.getMethod("annotatedOnLeaf", (Class[]) null);
assertNotNull(m.getAnnotation(Order.class));
assertNotNull(getAnnotation(m, Order.class));
......@@ -54,7 +54,7 @@ public class AnnotationUtilsTests {
}
@Test
public void testFindMethodAnnotationOnRoot() throws SecurityException, NoSuchMethodException {
public void findMethodAnnotationOnRoot() throws Exception {
Method m = Leaf.class.getMethod("annotatedOnRoot", (Class[]) null);
assertNotNull(m.getAnnotation(Order.class));
assertNotNull(getAnnotation(m, Order.class));
......@@ -62,7 +62,7 @@ public class AnnotationUtilsTests {
}
@Test
public void testFindMethodAnnotationOnRootButOverridden() throws SecurityException, NoSuchMethodException {
public void findMethodAnnotationOnRootButOverridden() throws Exception {
Method m = Leaf.class.getMethod("overrideWithoutNewAnnotation", (Class[]) null);
assertNull(m.getAnnotation(Order.class));
assertNull(getAnnotation(m, Order.class));
......@@ -70,13 +70,13 @@ public class AnnotationUtilsTests {
}
@Test
public void testFindMethodAnnotationNotAnnotated() throws SecurityException, NoSuchMethodException {
public void findMethodAnnotationNotAnnotated() throws Exception {
Method m = Leaf.class.getMethod("notAnnotated", (Class[]) null);
assertNull(findAnnotation(m, Order.class));
}
@Test
public void testFindMethodAnnotationOnBridgeMethod() throws Exception {
public void findMethodAnnotationOnBridgeMethod() throws Exception {
Method m = SimpleFoo.class.getMethod("something", Object.class);
assertTrue(m.isBridge());
assertNull(m.getAnnotation(Order.class));
......@@ -88,7 +88,7 @@ public class AnnotationUtilsTests {
}
// TODO consider whether we want this to handle annotations on interfaces
// public void testFindMethodAnnotationFromInterfaceImplementedByRoot()
// public void findMethodAnnotationFromInterfaceImplementedByRoot()
// throws Exception {
// Method m = Leaf.class.getMethod("fromInterfaceImplementedByRoot",
// (Class[]) null);
......@@ -241,7 +241,7 @@ public class AnnotationUtilsTests {
}
@Test
public void testGetValueFromAnnotation() throws Exception {
public void getValueFromAnnotation() throws Exception {
Method method = SimpleFoo.class.getMethod("something", Object.class);
Order order = findAnnotation(method, Order.class);
......@@ -250,7 +250,18 @@ public class AnnotationUtilsTests {
}
@Test
public void testGetDefaultValueFromAnnotation() throws Exception {
public void getValueFromNonPublicAnnotation() throws Exception {
Annotation[] declaredAnnotations = NonPublicAnnotatedClass.class.getDeclaredAnnotations();
assertEquals(1, declaredAnnotations.length);
Annotation annotation = declaredAnnotations[0];
assertNotNull(annotation);
assertEquals("NonPublicAnnotation", annotation.annotationType().getSimpleName());
assertEquals(42, AnnotationUtils.getValue(annotation, AnnotationUtils.VALUE));
assertEquals(42, AnnotationUtils.getValue(annotation));
}
@Test
public void getDefaultValueFromAnnotation() throws Exception {
Method method = SimpleFoo.class.getMethod("something", Object.class);
Order order = findAnnotation(method, Order.class);
......@@ -259,34 +270,46 @@ public class AnnotationUtilsTests {
}
@Test
public void testGetDefaultValueFromAnnotationType() throws Exception {
public void getDefaultValueFromNonPublicAnnotation() throws Exception {
Annotation[] declaredAnnotations = NonPublicAnnotatedClass.class.getDeclaredAnnotations();
assertEquals(1, declaredAnnotations.length);
Annotation annotation = declaredAnnotations[0];
assertNotNull(annotation);
assertEquals("NonPublicAnnotation", annotation.annotationType().getSimpleName());
assertEquals(-1, AnnotationUtils.getDefaultValue(annotation, AnnotationUtils.VALUE));
assertEquals(-1, AnnotationUtils.getDefaultValue(annotation));
}
@Test
public void getDefaultValueFromAnnotationType() throws Exception {
assertEquals(Ordered.LOWEST_PRECEDENCE, AnnotationUtils.getDefaultValue(Order.class, AnnotationUtils.VALUE));
assertEquals(Ordered.LOWEST_PRECEDENCE, AnnotationUtils.getDefaultValue(Order.class));
}
@Test
public void testFindAnnotationFromInterface() throws Exception {
public void findAnnotationFromInterface() throws Exception {
Method method = ImplementsInterfaceWithAnnotatedMethod.class.getMethod("foo");
Order order = findAnnotation(method, Order.class);
assertNotNull(order);
}
@Test
public void testFindAnnotationFromInterfaceOnSuper() throws Exception {
public void findAnnotationFromInterfaceOnSuper() throws Exception {
Method method = SubOfImplementsInterfaceWithAnnotatedMethod.class.getMethod("foo");
Order order = findAnnotation(method, Order.class);
assertNotNull(order);
}
@Test
public void testFindAnnotationFromInterfaceWhenSuperDoesNotImplementMethod() throws Exception {
public void findAnnotationFromInterfaceWhenSuperDoesNotImplementMethod()
throws Exception {
Method method = SubOfAbstractImplementsInterfaceWithAnnotatedMethod.class.getMethod("foo");
Order order = findAnnotation(method, Order.class);
assertNotNull(order);
}
@Test
public void testGetRepeatableFromMethod() throws Exception {
public void getRepeatableFromMethod() throws Exception {
Method method = InterfaceWithRepeated.class.getMethod("foo");
Set<MyRepeatable> annotions = AnnotationUtils.getRepeatableAnnotation(method,
MyRepeatableContainer.class, MyRepeatable.class);
......@@ -319,6 +342,7 @@ public class AnnotationUtilsTests {
static class ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface implements InterfaceWithMetaAnnotation {
}
public static interface AnnotatedInterface {
@Order(0)
......
/*
* Copyright 2002-2013 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
*
* http://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.core.annotation.subpackage;
/**
* Class annotated with a non-public (i.e., package private) custom annotation.
*
* @author Sam Brannen
* @since 4.0
*/
@NonPublicAnnotation(42)
public class NonPublicAnnotatedClass {
}
/*
* Copyright 2002-2013 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
*
* http://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.core.annotation.subpackage;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Non-public (i.e., package private) custom annotation.
*
* @author Sam Brannen
* @since 4.0
*/
@Retention(RetentionPolicy.RUNTIME)
@interface NonPublicAnnotation {
int value() default -1;
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册