问题
I have a domain object, that for the purposes of this question I will call Person with the following private variables:
String name
int age
Each of these have getters and setters. Now I also have a Map<String, String>
with the following entries:
name, phil
age, 35
I would like to populate a list of all setter methods within the class Person and then looping through this list and invoking each method using the values from the map.
Is this even possible as I cannot see any examples close to this on the net. Examples are very much appreciated.
回答1:
Sure it's possible! You can get all methods that start with "set" back by doing this:
Class curClass = myclass.class;
Method[] allMethods = curClass.getMethods();
List<Method> setters = new ArrayList<Method>();
for(Method method : allMethods) {
if(method.getName().startsWith("set")) {
setters.add(method);
}
}
Now you've got the methods. Do you already know how to call them for your instance of the class?
回答2:
Have you tried BeanUtils.populate()) from Apache Commons BeanUtils?
BeanUtils.populate(yourObject, propertiesMap);
回答3:
I think you could use a library, the Apache Commons BeanUtils. If you have a map that contains field and value pairs, the class PropertyUtils can help you:
Person person = new Person();
for(Map.Entry<String, Object> entry : map.entrySet())
PropertyUtils.setProperty(person, entry.getKey(), entry.getValue());
回答4:
This is a full solution that verifies output class beforehand and consequently calls setters for all the properties that the map contains. It uses purely java.beans
and java.lang.reflect
.
public Object mapToObject(Map<String, Object> input, Class<?> outputType) {
Object outputObject = null;
List<PropertyDescriptor> outputPropertyDescriptors = null;
// Test if class is instantiable with default constructor
if(isInstantiable(outputType)
&& hasDefaultConstructor(outputType)
&& (outputPropertyDescriptors = getPropertyDescriptors(outputType)) != null) {
try {
outputObject = outputType.getConstructor().newInstance();
for(PropertyDescriptor pd : outputPropertyDescriptors) {
Object value = input.get(pd.getName());
if(value != null) {
pd.getWriteMethod().invoke(outputObject, value);
}
}
} catch (InstantiationException|IllegalAccessException|InvocationTargetException|NoSuchMethodException e) {
throw new IllegalStateException("Failed to instantiate verified class " + outputType, e);
}
} else {
throw new IllegalArgumentException("Specified outputType class " + outputType + "cannot be instantiated with default constructor!");
}
return outputObject;
}
private List<PropertyDescriptor> getPropertyDescriptors(Class<?> outputType) {
List<PropertyDescriptor> propertyDescriptors = null;
try {
propertyDescriptors = Arrays.asList(Introspector.getBeanInfo(outputType, Object.class).getPropertyDescriptors());
} catch (IntrospectionException e) {
}
return propertyDescriptors;
}
private boolean isInstantiable(Class<?> clazz) {
return ! clazz.isInterface() && ! Modifier.isAbstract(clazz.getModifiers());
}
private boolean hasDefaultConstructor(Class<?> clazz) {
try {
clazz.getConstructor();
return true;
} catch (NoSuchMethodException e) {
return false;
}
}
来源:https://stackoverflow.com/questions/10506960/invoking-all-setters-within-a-class-using-reflection