ReflectionUtils.java
package org.codehaus.plexus.util;
/*
* Copyright The Codehaus Foundation.
*
* 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.
*/
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Operations on a class' fields and their setters.
*
* @author <a href="mailto:michal@codehaus.org">Michal Maczka</a>
* @author <a href="mailto:jesse@codehaus.org">Jesse McConnell</a>
* @author <a href="mailto:trygvis@inamo.no">Trygve Laugstøl</a>
*/
public final class ReflectionUtils {
// ----------------------------------------------------------------------
// Field utils
// ----------------------------------------------------------------------
public static Field getFieldByNameIncludingSuperclasses(String fieldName, Class<?> clazz) {
Field retValue = null;
try {
retValue = clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
Class<?> superclass = clazz.getSuperclass();
if (superclass != null) {
retValue = getFieldByNameIncludingSuperclasses(fieldName, superclass);
}
}
return retValue;
}
public static List<Field> getFieldsIncludingSuperclasses(Class<?> clazz) {
List<Field> fields = new ArrayList<>(Arrays.asList(clazz.getDeclaredFields()));
Class<?> superclass = clazz.getSuperclass();
if (superclass != null) {
fields.addAll(getFieldsIncludingSuperclasses(superclass));
}
return fields;
}
// ----------------------------------------------------------------------
// Setter utils
// ----------------------------------------------------------------------
/**
* Finds a setter in the given class for the given field. It searches interfaces and superclasses too.
*
* @param fieldName the name of the field (i.e. 'fooBar'); it will search for a method named 'setFooBar'.
* @param clazz The class to find the method in.
* @return null or the method found.
*/
public static Method getSetter(String fieldName, Class<?> clazz) {
Method[] methods = clazz.getMethods();
fieldName = "set" + StringUtils.capitalizeFirstLetter(fieldName);
for (Method method : methods) {
if (method.getName().equals(fieldName) && isSetter(method)) {
return method;
}
}
return null;
}
/**
* @return all setters in the given class and super classes.
* @param clazz the Class
*/
public static List<Method> getSetters(Class<?> clazz) {
Method[] methods = clazz.getMethods();
List<Method> list = new ArrayList<>();
for (Method method : methods) {
if (isSetter(method)) {
list.add(method);
}
}
return list;
}
/**
* @param method the method
* @return the class of the argument to the setter. Will throw an RuntimeException if the method isn't a setter.
*/
public static Class<?> getSetterType(Method method) {
if (!isSetter(method)) {
throw new RuntimeException("The method "
+ method.getDeclaringClass().getName() + "." + method.getName() + " is not a setter.");
}
return method.getParameterTypes()[0];
}
// ----------------------------------------------------------------------
// Value accesstors
// ----------------------------------------------------------------------
/**
* attempts to set the value to the variable in the object passed in
*
* @param object see name
* @param variable see name
* @param value see name
* @throws IllegalAccessException if error
*/
public static void setVariableValueInObject(Object object, String variable, Object value)
throws IllegalAccessException {
Field field = getFieldByNameIncludingSuperclasses(variable, object.getClass());
field.setAccessible(true);
field.set(object, value);
}
/**
* Generates a map of the fields and values on a given object, also pulls from superclasses
*
* @param variable field name
* @param object the object to generate the list of fields from
* @return map containing the fields and their values
* @throws IllegalAccessException cannot access
*/
public static Object getValueIncludingSuperclasses(String variable, Object object) throws IllegalAccessException {
Field field = getFieldByNameIncludingSuperclasses(variable, object.getClass());
field.setAccessible(true);
return field.get(object);
}
/**
* Generates a map of the fields and values on a given object, also pulls from superclasses
*
* @param object the object to generate the list of fields from
* @return map containing the fields and their values
* @throws IllegalAccessException cannot access
*/
public static Map<String, Object> getVariablesAndValuesIncludingSuperclasses(Object object)
throws IllegalAccessException {
Map<String, Object> map = new HashMap<>();
gatherVariablesAndValuesIncludingSuperclasses(object, map);
return map;
}
// ----------------------------------------------------------------------
// Private
// ----------------------------------------------------------------------
public static boolean isSetter(Method method) {
return method.getReturnType().equals(Void.TYPE)
&& // FIXME: needed /required?
!Modifier.isStatic(method.getModifiers())
&& method.getParameterTypes().length == 1;
}
/**
* populates a map of the fields and values on a given object, also pulls from superclasses
*
* @param object the object to generate the list of fields from
* @param map to populate
*/
private static void gatherVariablesAndValuesIncludingSuperclasses(Object object, Map<String, Object> map)
throws IllegalAccessException {
Class<?> clazz = object.getClass();
if (Float.parseFloat(System.getProperty("java.specification.version")) >= 11
&& Class.class.getCanonicalName().equals(clazz.getCanonicalName())) {
// Updating Class fields accessibility is forbidden on Java 16 (and throws warning from version 11)
// No concrete use case to modify accessibility at this level
return;
}
Field[] fields = clazz.getDeclaredFields();
AccessibleObject.setAccessible(fields, true);
for (Field field : fields) {
map.put(field.getName(), field.get(object));
}
Class<?> superclass = clazz.getSuperclass();
if (!Object.class.equals(superclass)) {
gatherVariablesAndValuesIncludingSuperclasses(superclass, map);
}
}
}