Mainly, there are several solutions for obtaining the getters and setters of a class via reflection. Let's assume that we want to fetch the getters and setters of the following Melon class:
public class Melon {
private String type;
private int weight;
private boolean ripe;
...
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public boolean isRipe() {
return ripe;
}
public void setRipe(boolean ripe) {
this.ripe = ripe;
}
...
}
Let's start with a solution that gets all the declared methods of a class via reflection (for example, via Class.getDeclaredMethods()). Now, loop Method[] and filter it by constraints that are specific to getters and setters (for example, start with the get/set prefix, return void or a certain type, and so on).
Another solution is getting all the declared fields of a class via reflection (for example, via Class.getDeclaredFields()). Now, loop Field[] and try to obtain the getters and setters via Class.getDeclaredMethod() by passing the name of the field (prefixed with get/set/is and the first letter capitalized) and the type of the field (in the case of setters) to it.
Finally, a more elegant solution will rely on the PropertyDescriptor and Introspector APIs. These APIs are available in the java.beans.* package and are dedicated to working with JavaBeans.
The PropertyDescriptor class can return the method that's used for reading a JavaBean property via getReadMethod(). Moreover, it can return the method that's used for writing a JavaBean property via getWriteMethod(). Relying on these two methods, we can fetch the getters and setters of the Melon class, as follows:
for (PropertyDescriptor pd:
Introspector.getBeanInfo(Melon.class).getPropertyDescriptors()) {
if (pd.getReadMethod() != null && !"class".equals(pd.getName())) {
System.out.println(pd.getReadMethod());
}
if (pd.getWriteMethod() != null && !"class".equals(pd.getName())) {
System.out.println(pd.getWriteMethod());
}
}
The output is as follows:
public boolean modern.challenge.Melon.isRipe()
public void modern.challenge.Melon.setRipe(boolean)
public java.lang.String modern.challenge.Melon.getType()
public void modern.challenge.Melon.setType(java.lang.String)
public int modern.challenge.Melon.getWeight()
public void modern.challenge.Melon.setWeight(int)
Now, let's assume that we have the following Melon instance:
Melon melon = new Melon("Gac", 1000);
Here, we want to call the getType() getter:
// the returned type is Gac
Object type = new PropertyDescriptor("type",
Melon.class).getReadMethod().invoke(melon);
Now, let's call the setWeight() setter:
// set weight of Gac to 2000
new PropertyDescriptor("weight", Melon.class)
.getWriteMethod().invoke(melon, 2000);
Calling for an inexistent property will cause IntrospectionException:
try {
Object shape = new PropertyDescriptor("shape",
Melon.class).getReadMethod().invoke(melon);
System.out.println("Melon shape: " + shape);
} catch (IntrospectionException e) {
System.out.println("Property not found: " + e);
}