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 extends Annotation> 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;
+}