You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by br...@apache.org on 2014/07/20 11:15:04 UTC

svn commit: r1612063 - in /commons/proper/lang/trunk/src: changes/ main/java/org/apache/commons/lang3/reflect/ test/java/org/apache/commons/lang3/reflect/ test/java/org/apache/commons/lang3/reflect/testbed/

Author: britter
Date: Sun Jul 20 09:15:04 2014
New Revision: 1612063

URL: http://svn.apache.org/r1612063
Log:
LANG-1021: Provide methods to retrieve all fields/methods annotated with a specific type. Thanks to Alexander Müller.

Added:
    commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/reflect/testbed/Annotated.java
Modified:
    commons/proper/lang/trunk/src/changes/changes.xml
    commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/reflect/FieldUtils.java
    commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java
    commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/reflect/FieldUtilsTest.java
    commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/reflect/MethodUtilsTest.java

Modified: commons/proper/lang/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/changes/changes.xml?rev=1612063&r1=1612062&r2=1612063&view=diff
==============================================================================
--- commons/proper/lang/trunk/src/changes/changes.xml [utf-8] (original)
+++ commons/proper/lang/trunk/src/changes/changes.xml [utf-8] Sun Jul 20 09:15:04 2014
@@ -22,6 +22,7 @@
   <body>
 
   <release version="3.4" date="tba" description="tba">
+    <action issue="LANG-1021" type="add" dev="britter" due-to="Alexander Müller">Provide methods to retrieve all fields/methods annotated with a specific type</action>
     <action issue="LANG-1026" type="update" dev="britter" due-to="Alex Yursha">Bring static method references in StringUtils to consistent style</action>
     <action issue="LANG-1016" type="add" dev="britter" due-to="Juan Pablo Santos Rodríguez">NumberUtils#isParsable method(s)</action>
     <action issue="LANG-1017" type="update" dev="britter" due-to="Christoph Schneegans">Use non-ASCII digits in Javadoc examples for StringUtils.isNumeric</action>

Modified: commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/reflect/FieldUtils.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/reflect/FieldUtils.java?rev=1612063&r1=1612062&r2=1612063&view=diff
==============================================================================
--- commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/reflect/FieldUtils.java (original)
+++ commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/reflect/FieldUtils.java Sun Jul 20 09:15:04 2014
@@ -20,6 +20,7 @@ import org.apache.commons.lang3.ClassUti
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.Validate;
 
+import java.lang.annotation.Annotation;
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
@@ -223,6 +224,45 @@ public class FieldUtils {
     }
 
     /**
+     * Gets all fields of the given class and its parents (if any) that are annotated with the given annotation.
+     * @param cls
+     *            the {@link Class} to query
+     * @param annotationCls
+     *            the {@link Annotation} that must be present on a field to be matched
+     * @return an array of Fields (possibly empty).
+     * @throws IllegalArgumentException
+     *            if the class or annotation are {@code null}
+     * @since 3.4
+     */
+    public static Field[] getFieldsWithAnnotation(final Class<?> cls, final Class<? extends Annotation> annotationCls) {
+        final List<Field> annotatedFieldsList = getFieldsListWithAnnotation(cls, annotationCls);
+        return annotatedFieldsList.toArray(new Field[annotatedFieldsList.size()]);
+    }
+
+    /**
+     * Gets all fields of the given class and its parents (if any) that are annotated with the given annotation.
+     * @param cls
+     *            the {@link Class} to query
+     * @param annotationCls
+     *            the {@link Annotation} that must be present on a field to be matched
+     * @return a list of Fields (possibly empty).
+     * @throws IllegalArgumentException
+     *            if the class or annotation are {@code null}
+     * @since 3.4
+     */
+    public static List<Field> getFieldsListWithAnnotation(final Class<?> cls, final Class<? extends Annotation> annotationCls) {
+        Validate.isTrue(annotationCls != null, "The annotation class must not be null");
+        final List<Field> allFields = getAllFieldsList(cls);
+        final List<Field> annotatedFields = new ArrayList<Field>();
+        for (final Field field : allFields) {
+            if (field.getAnnotation(annotationCls) != null) {
+                annotatedFields.add(field);
+            }
+        }
+        return annotatedFields;
+    }
+
+    /**
      * Reads an accessible {@code static} {@link Field}.
      * 
      * @param field

Modified: commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java?rev=1612063&r1=1612062&r2=1612063&view=diff
==============================================================================
--- commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java (original)
+++ commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/reflect/MethodUtils.java Sun Jul 20 09:15:04 2014
@@ -16,14 +16,17 @@
  */
 package org.apache.commons.lang3.reflect;
 
+import java.lang.annotation.Annotation;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Type;
 import java.lang.reflect.TypeVariable;
 import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.LinkedHashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -546,4 +549,44 @@ public class MethodUtils {
         return result;
     }
 
+    /**
+     * Gets all methods of the given class that are annotated with the given annotation.
+     * @param cls
+     *            the {@link Class} to query
+     * @param annotationCls
+     *            the {@link java.lang.annotation.Annotation} that must be present on a method to be matched
+     * @return an array of Methods (possibly empty).
+     * @throws IllegalArgumentException
+     *            if the class or annotation are {@code null}
+     * @since 3.4
+     */
+    public static Method[] getMethodsWithAnnotation(final Class<?> cls, final Class<? extends Annotation> annotationCls) {
+        final List<Method> annotatedMethodsList = getMethodsListWithAnnotation(cls, annotationCls);
+        return annotatedMethodsList.toArray(new Method[annotatedMethodsList.size()]);
+    }
+
+    /**
+     * Gets all methods of the given class that are annotated with the given annotation.
+     * @param cls
+     *            the {@link Class} to query
+     * @param annotationCls
+     *            the {@link Annotation} that must be present on a method to be matched
+     * @return a list of Methods (possibly empty).
+     * @throws IllegalArgumentException
+     *            if the class or annotation are {@code null}
+     * @since 3.4
+     */
+    public static List<Method> getMethodsListWithAnnotation(final Class<?> cls, final Class<? extends Annotation> annotationCls) {
+        Validate.isTrue(cls != null, "The class must not be null");
+        Validate.isTrue(annotationCls != null, "The annotation class must not be null");
+        final Method[] allMethods = cls.getMethods();
+        final List<Method> annotatedMethods = new ArrayList<Method>();
+        for (final Method method : allMethods) {
+            if (method.getAnnotation(annotationCls) != null) {
+                annotatedMethods.add(method);
+            }
+        }
+        return annotatedMethods;
+    }
+
 }

Modified: commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/reflect/FieldUtilsTest.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/reflect/FieldUtilsTest.java?rev=1612063&r1=1612062&r2=1612063&view=diff
==============================================================================
--- commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/reflect/FieldUtilsTest.java (original)
+++ commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/reflect/FieldUtilsTest.java Sun Jul 20 09:15:04 2014
@@ -43,8 +43,10 @@ public class FieldUtilsTest {
     static final Double D0 = Double.valueOf(0.0);
     static final Double D1 = Double.valueOf(1.0);
 
+    @Annotated
     private PublicChild publicChild;
     private PubliclyShadowedChild publiclyShadowedChild;
+    @Annotated
     private PrivatelyShadowedChild privatelyShadowedChild;
     private final Class<? super PublicChild> parentClass = PublicChild.class.getSuperclass();
 
@@ -167,6 +169,59 @@ public class FieldUtilsTest {
     }
 
     @Test
+    public void testGetFieldsWithAnnotation() throws NoSuchFieldException {
+        assertArrayEquals(new Field[0], FieldUtils.getFieldsWithAnnotation(Object.class, Annotated.class));
+        final Field[] annotatedFields = new Field[]{
+                FieldUtilsTest.class.getDeclaredField("publicChild"),
+                FieldUtilsTest.class.getDeclaredField("privatelyShadowedChild")
+        };
+        assertArrayEquals(annotatedFields, FieldUtils.getFieldsWithAnnotation(FieldUtilsTest.class, Annotated.class));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetFieldsWithAnnotationIllegalArgumentException1() {
+        FieldUtils.getFieldsWithAnnotation(FieldUtilsTest.class, null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetFieldsWithAnnotationIllegalArgumentException2() {
+        FieldUtils.getFieldsWithAnnotation(null, Annotated.class);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetFieldsWithAnnotationIllegalArgumentException3() {
+        FieldUtils.getFieldsWithAnnotation(null, null);
+    }
+
+    @Test
+    public void testGetFieldsListWithAnnotation() throws NoSuchFieldException {
+        assertEquals(0, FieldUtils.getFieldsListWithAnnotation(Object.class, Annotated.class).size());
+        final List<Field> annotatedFields = Arrays.asList(
+                FieldUtilsTest.class.getDeclaredField("publicChild"),
+                FieldUtilsTest.class.getDeclaredField("privatelyShadowedChild")
+        );
+        final List<Field> fieldUtilsTestAnnotatedFields = FieldUtils.getFieldsListWithAnnotation(FieldUtilsTest.class, Annotated.class);
+        assertEquals(annotatedFields.size(),fieldUtilsTestAnnotatedFields.size());
+        assertTrue(fieldUtilsTestAnnotatedFields.contains(annotatedFields.get(0)));
+        assertTrue(fieldUtilsTestAnnotatedFields.contains(annotatedFields.get(1)));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetFieldsListWithAnnotationIllegalArgumentException1() {
+        FieldUtils.getFieldsListWithAnnotation(FieldUtilsTest.class, null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetFieldsListWithAnnotationIllegalArgumentException2() {
+        FieldUtils.getFieldsListWithAnnotation(null, Annotated.class);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetFieldsListWithAnnotationIllegalArgumentException3() {
+        FieldUtils.getFieldsListWithAnnotation(null, null);
+    }
+
+    @Test
     public void testGetDeclaredField() {
         assertNull(FieldUtils.getDeclaredField(PublicChild.class, "VALUE"));
         assertNull(FieldUtils.getDeclaredField(PublicChild.class, "s"));
@@ -818,28 +873,28 @@ public class FieldUtilsTest {
         assertEquals("new", StaticContainer.getMutablePrivate());
         field = StaticContainer.class.getDeclaredField("IMMUTABLE_PUBLIC");
         try {
-        FieldUtils.writeStaticField(field, "new", true);
+            FieldUtils.writeStaticField(field, "new", true);
             fail("Expected IllegalAccessException");
         } catch (final IllegalAccessException e) {
             // pass
         }
         field = StaticContainer.class.getDeclaredField("IMMUTABLE_PROTECTED");
         try {
-        FieldUtils.writeStaticField(field, "new", true);
+            FieldUtils.writeStaticField(field, "new", true);
             fail("Expected IllegalAccessException");
         } catch (final IllegalAccessException e) {
             // pass
         }
         field = StaticContainer.class.getDeclaredField("IMMUTABLE_PACKAGE");
         try {
-        FieldUtils.writeStaticField(field, "new", true);
+            FieldUtils.writeStaticField(field, "new", true);
             fail("Expected IllegalAccessException");
         } catch (final IllegalAccessException e) {
             // pass
         }
         field = StaticContainer.class.getDeclaredField("IMMUTABLE_PRIVATE");
         try {
-        FieldUtils.writeStaticField(field, "new", true);
+            FieldUtils.writeStaticField(field, "new", true);
             fail("Expected IllegalAccessException");
         } catch (final IllegalAccessException e) {
             // pass

Modified: commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/reflect/MethodUtilsTest.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/reflect/MethodUtilsTest.java?rev=1612063&r1=1612062&r2=1612063&view=diff
==============================================================================
--- commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/reflect/MethodUtilsTest.java (original)
+++ commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/reflect/MethodUtilsTest.java Sun Jul 20 09:15:04 2014
@@ -16,6 +16,7 @@
  */
 package org.apache.commons.lang3.reflect;
 
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -30,6 +31,7 @@ import java.lang.reflect.Type;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 
 import org.apache.commons.lang3.ArrayUtils;
@@ -37,6 +39,7 @@ import org.apache.commons.lang3.math.Num
 import org.apache.commons.lang3.mutable.Mutable;
 import org.apache.commons.lang3.mutable.MutableObject;
 import org.apache.commons.lang3.ClassUtils.Interfaces;
+import org.apache.commons.lang3.reflect.testbed.Annotated;
 import org.apache.commons.lang3.reflect.testbed.GenericConsumer;
 import org.apache.commons.lang3.reflect.testbed.GenericParent;
 import org.apache.commons.lang3.reflect.testbed.StringParameterizedChild;
@@ -424,6 +427,61 @@ public class MethodUtilsTest {
         }
         assertFalse(expected.hasNext());
     }
+
+    @Test
+    @Annotated
+    public void testGetMethodsWithAnnotation() throws NoSuchMethodException {
+        assertArrayEquals(new Method[0], MethodUtils.getMethodsWithAnnotation(Object.class, Annotated.class));
+        final Method[] annotatedMethods = new Method[]{
+                MethodUtilsTest.class.getMethod("testGetMethodsWithAnnotation"),
+                MethodUtilsTest.class.getMethod("testGetMethodsListWithAnnotation")
+        };
+        assertArrayEquals(annotatedMethods, MethodUtils.getMethodsWithAnnotation(MethodUtilsTest.class, Annotated.class));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetMethodsWithAnnotationIllegalArgumentException1() {
+        MethodUtils.getMethodsWithAnnotation(FieldUtilsTest.class, null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetMethodsWithAnnotationIllegalArgumentException2() {
+        MethodUtils.getMethodsWithAnnotation(null, Annotated.class);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetMethodsWithAnnotationIllegalArgumentException3() {
+        MethodUtils.getMethodsWithAnnotation(null, null);
+    }
+
+    @Test
+    @Annotated
+    public void testGetMethodsListWithAnnotation() throws NoSuchMethodException {
+        assertEquals(0, MethodUtils.getMethodsListWithAnnotation(Object.class, Annotated.class).size());
+        final List<Method> annotatedMethods = Arrays.asList(
+                MethodUtilsTest.class.getMethod("testGetMethodsWithAnnotation"),
+                MethodUtilsTest.class.getMethod("testGetMethodsListWithAnnotation")
+        );
+        final List<Method> methodUtilsTestAnnotatedFields = MethodUtils.getMethodsListWithAnnotation(MethodUtilsTest.class, Annotated.class);
+        assertEquals(annotatedMethods.size(), methodUtilsTestAnnotatedFields.size());
+        assertTrue(methodUtilsTestAnnotatedFields.contains(annotatedMethods.get(0)));
+        assertTrue(methodUtilsTestAnnotatedFields.contains(annotatedMethods.get(1)));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetMethodsListWithAnnotationIllegalArgumentException1() {
+        MethodUtils.getMethodsListWithAnnotation(FieldUtilsTest.class, null);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetMethodsListWithAnnotationIllegalArgumentException2() {
+        MethodUtils.getMethodsListWithAnnotation(null, Annotated.class);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGetMethodsListWithAnnotationIllegalArgumentException3() {
+        MethodUtils.getMethodsListWithAnnotation(null, null);
+    }
     
     private void expectMatchingAccessibleMethodParameterTypes(final Class<?> cls,
             final String methodName, final Class<?>[] requestTypes, final Class<?>[] actualTypes) {

Added: commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/reflect/testbed/Annotated.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/reflect/testbed/Annotated.java?rev=1612063&view=auto
==============================================================================
--- commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/reflect/testbed/Annotated.java (added)
+++ commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/reflect/testbed/Annotated.java Sun Jul 20 09:15:04 2014
@@ -0,0 +1,11 @@
+package org.apache.commons.lang3.reflect.testbed;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD, ElementType.METHOD})
+public @interface Annotated {
+}