Reputation: 2708
I need to invoke the setter methods of a class using reflection, and the code is as below:
try {
Method method = myObj.getClass().getMethod("set" + fieldName, new Class[] { value.getClass() });
method.invoke(myObj, value);
} catch (Exception ex) {
ex.printStackTrace();
}
The value
is an ArrayList
and the setter method is as below:
public void setNames(List<String> names){
this.names = names;
}
A java.lang.NoSuchMethodException
is thrown when running this code, but when the setter method parameter type is changed to ArrayList
from List
it executes fine. Is there a way to keep the setter method parameter in super type and still use reflection without manually giving the type of the parameter when getting the method from the class?
Upvotes: 58
Views: 104794
Reputation: 41
Reflection Class is sometimes called as dynamic invocation.
for example, lets look around getter methods using reflection
consider there is a class called MyReflectionClass
and has a method called getreflect()
. (eg type string)
lets see how to use reflection classes
MyReflectionClass obj = new MyReflectionClass();
<? extends MyReflectionClass> tempClass = obj.getClass();
String a = (String) obj.getMethod("getreflect").invoke(obj);
now setter method
(String) obj.getDeclaredMethod("setreflect", String.class).invoke(obj,"MyString");
if you need to do the same operation with sequence of string then
(String) obj.getDeclaredMethod("setreflect",
new String.class{}).invoke(obj,"MyString1","MyString2");
hope it may be useful
Upvotes: 4
Reputation: 75
Detecting Method Names using String Handling might not look like right way of doing it. Consider this as one of the solutions.
try {
Animal animal = new Animal();
BeanInfo beaninfo = Introspector.getBeanInfo(Animal.class);
PropertyDescriptor pds[] = beaninfo.getPropertyDescriptors();
Method setterMethod=null;
for(PropertyDescriptor pd : pds) {
setterMethod = pd.getWriteMethod(); // For Setter Method
/*
You can get Various property of Classes you want.
*/
System.out.println(pd.getName().toString()+ "--> "+pd.getPropertyType().toString()+"--Setter Method:->"+pd.getWriteMethod().toString());
if(setterMethod == null) continue;
else
setterMethod.invoke(animal, "<value>");
}
}catch(Exception e) {e.printStackTrace();}
Upvotes: 0
Reputation: 1871
You could use BeanUtils:
Step #1
Customer customer = new Customer();
Step #2
BeanUtils.setProperty(customer,"firstName","Paul Young");
You could iterate all class members using reflection and set values accordingly, assuming customer object has:
private String firstName;
// Getter and Setter are defined
Upvotes: 61
Reputation: 5350
If you happen to use spring framework, you could use the PropertyAccessorFactory for retrieving an implementation of the PropertyAccessor interface:
PropertyAccessor myAccessor = PropertyAccessorFactory.forDirectFieldAccess(object);
// set the property directly, bypassing the mutator (if any)
myAccessor.setPropertyValue("someProperty", "some value");
If you need to access your properties using their getters and setters, you could use instead the forBeanPropertyAccess
method:
PropertyAccessor myAccessor = PropertyAccessorFactory.forBeanPropertyAccess(object);
// a `setSomeProperty()` method will be used
myAccessor.setPropertyValue("someProperty", "some value");
Upvotes: 63
Reputation: 74
Example set All filds using the setters methods geting the values with ResultSet.
private Object setAllSetters(Object ob, ResultSet rs) throws SQLException{
// MZ: Find the correct method
Class cls = ob.getClass();
while (rs.next()) {
for (Field field : cls.getDeclaredFields()){
for (Method method : cls.getMethods())
{
if ((method.getName().startsWith("set")) && (method.getName().length() == (field.getName().length() + 3)))
{
if (method.getName().toLowerCase().endsWith(field.getName().toLowerCase()))
{
// MZ: Method found, run it
try
{
method.setAccessible(true);
if(field.getType().getSimpleName().toLowerCase().endsWith("integer"))
method.invoke(ob,rs.getInt(field.getName().toLowerCase()));
else if(field.getType().getSimpleName().toLowerCase().endsWith("long"))
method.invoke(ob,rs.getLong(field.getName().toLowerCase()));
else if(field.getType().getSimpleName().toLowerCase().endsWith("string"))
method.invoke(ob,rs.getString(field.getName().toLowerCase()));
else if(field.getType().getSimpleName().toLowerCase().endsWith("boolean"))
method.invoke(ob,rs.getBoolean(field.getName().toLowerCase()));
else if(field.getType().getSimpleName().toLowerCase().endsWith("timestamp"))
method.invoke(ob,rs.getTimestamp(field.getName().toLowerCase()));
else if(field.getType().getSimpleName().toLowerCase().endsWith("date"))
method.invoke(ob,rs.getDate(field.getName().toLowerCase()));
else if(field.getType().getSimpleName().toLowerCase().endsWith("double"))
method.invoke(ob,rs.getDouble(field.getName().toLowerCase()));
else if(field.getType().getSimpleName().toLowerCase().endsWith("float"))
method.invoke(ob,rs.getFloat(field.getName().toLowerCase()));
else if(field.getType().getSimpleName().toLowerCase().endsWith("time"))
method.invoke(ob,rs.getTime(field.getName().toLowerCase()));
else
method.invoke(ob,rs.getObject(field.getName().toLowerCase()));
}
catch (IllegalAccessException | InvocationTargetException | SQLException e)
{
System.err.println(e.getMessage());
}
}
}
}
}
}
return ob;
}
Upvotes: 1
Reputation: 36577
There is a simple solution, but that simplicity comes at the cost of performance.
I'm using this monster instead:
public static Method findMethod(Class<?> clazz, String methodName, Class<?>... parameterTypes) throws NoSuchMethodException {
// First try the trivial approach. This works usually, but not always.
try {
return clazz.getMethod(methodName, parameterTypes);
} catch (NoSuchMethodException ex) {
}
// Then loop through all available methods, checking them one by one.
for (Method method : clazz.getMethods()) {
String name = method.getName();
if (!methodName.equals(name)) { // The method must have right name.
continue;
}
Class<?>[] acceptedParameterTypes = method.getParameterTypes();
if (acceptedParameterTypes.length != parameterTypes.length) { // Must have right number of parameters.
continue;
}
boolean match = true;
for (int i = 0; i < acceptedParameterTypes.length; i++) { // All parameters must be right type.
if (null != parameterTypes[i] && !acceptedParameterTypes[i].isAssignableFrom(parameterTypes[i])) {
match = false;
break;
}
if (null == parameterTypes[i] && acceptedParameterTypes[i].isPrimitive()) { // Accept null except for primitive fields.
match = false;
break;
}
}
if (match) {
return method;
}
}
// None of our trials was successful!
throw new NoSuchMethodException();
}
parameterTypes
are what you get from your value.getClass()
. Some or all of them can be also null. Then they are treated as matces for any non-primitive parameter fields.
Even this isn't quit perfect: If there are several methods that are polymorphically suitable but none of which matches exactly, then the returned method is chosen arbitrarily (the first match in the array that clazz.getMethods()
returns is taken). This behavior differs from Java the Language behavior, in which the "closest match" is always used.
If getting the method by name is sufficient (i.e. you assume that the parameters are suitable if the name matches), then you can manage with much simpler (and somewhat faster):
public static Method findMethod(Class<?> clazz, String methodName) {
for (Method method : clazz.getMethods()) {
if (method.getName().equals(methodName)) {
return method;
}
}
throw new NoSuchMethodException();
}
To further boost it up, consider some sort of cache.
Upvotes: 5
Reputation: 310860
Contrary to other answers, there is a really simple solution. See java.beans.Statement
. It gives you a way to execute arbitrary reflective code without having to worry about actual vs formal types (and a few other things).
Upvotes: 29