diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java index e86ad1c6b524df6d278e8395ab64ed79042bc7fe..eb3595b85a00d235a0dff3a2e3b9243c50b2f1a4 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java @@ -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 { - private final Class containerAnnotationType; private final Class 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) { diff --git a/spring-core/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java b/spring-core/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java index e5ec3f1fc1cf795c963aa4af8c8ad6c4e834f1b1..0de78f64a01fef7a8a21dc8b0ba1c6eeebe84263 100644 --- a/spring-core/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java +++ b/spring-core/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java @@ -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 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) diff --git a/spring-core/src/test/java/org/springframework/core/annotation/subpackage/NonPublicAnnotatedClass.java b/spring-core/src/test/java/org/springframework/core/annotation/subpackage/NonPublicAnnotatedClass.java new file mode 100644 index 0000000000000000000000000000000000000000..7e79084ac88cd4682eec81f0cfde1b01b1e29608 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/annotation/subpackage/NonPublicAnnotatedClass.java @@ -0,0 +1,28 @@ +/* + * 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 { + +} diff --git a/spring-core/src/test/java/org/springframework/core/annotation/subpackage/NonPublicAnnotation.java b/spring-core/src/test/java/org/springframework/core/annotation/subpackage/NonPublicAnnotation.java new file mode 100644 index 0000000000000000000000000000000000000000..9f5e0d8892d62ae4ea736367f22dd490a08d14d3 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/annotation/subpackage/NonPublicAnnotation.java @@ -0,0 +1,32 @@ +/* + * 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; +}