LANG-1021: Provide methods to retrieve all fields/methods annotated with a specific type. Thanks to Alexander Müller.

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/lang/trunk@1612063 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Benedikt Ritter 2014-07-20 09:15:04 +00:00
parent 03aa1e7078
commit de67dec077
6 changed files with 212 additions and 4 deletions

View File

@ -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>

View File

@ -20,6 +20,7 @@ import org.apache.commons.lang3.ClassUtils;
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;
@ -222,6 +223,45 @@ public class FieldUtils {
return allFields;
}
/**
* 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}.
*

View File

@ -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;
}
}

View File

@ -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();
@ -166,6 +168,59 @@ public class FieldUtilsTest {
assertEquals(5, FieldUtils.getAllFieldsList(PublicChild.class).size());
}
@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"));
@ -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

View File

@ -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.NumberUtils;
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) {

View File

@ -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 {
}