I can access all methods of an IType
with the method getMethods()
. Is there an efficient way to determine if such an IMethod
is an accessor or a mutator (getter/setter)?
Checking if the name of an IMethod
matches the scheme prefix + NameOfAttribute
with prefix ∈ {"get", "set", "is"}
would help me to detect the obvious ones, but if an accessor or a mutator (getter/setter) is not named that way, it would not work.
Is there a better way?
EDIT: I only want to identify getter/setter methods that directly get/set an attribute of the IType
and do not do anything else.
EDIT2: Used technical terms: accessor & mutator
EDIT3: Here is my solution after reading all the answers:
private boolean isAccessor(IMethod method) throws JavaModelException {
if (isAccessMethod("get", method) || isAccessMethod("is", method)) { // if name fits
return method.getNumberOfParameters() == 0 && !Signature.SIG_VOID.equals(method.getReturnType());
}
return false;
}
private boolean isMutator(IMethod method) throws JavaModelException {
if (isAccessMethod("set", method)) { // if name fits
return method.getNumberOfParameters() == 1 && Signature.SIG_VOID.equals(method.getReturnType());
}
return false;
}
private boolean isAccessMethod(String prefix, IMethod method) throws JavaModelException {
IType type = method.getDeclaringType();
for (IField field : type.getFields()) { // for ever field of IType:
if (method.getElementName().equalsIgnoreCase(prefix + field.getElementName())) {
return true; // is access method if name scheme fits for one field
}
}
return false; // is not an access method if no field fits
}
IMPORTANT: This solution fits my requirements, but ignores some important cases (see the accepted answer). This still does not check the functionality of the method, but it works pretty well. It checks the method name for the scheme I proposed. But it also checks the parameter count and whether the return type is void
or not. If someone wanted to improve this he could also check whether the return/parameter type of the getter matches to the type of the field that was matched to the method name.
I guess that there is no support for identifying getters and setters in the JDT core.
There is only a public API in the JDT that provides getter/setter names generation based on field names. E.g. NamingConvention
Take a look at the suggestGetterName()
method.
Other internal classes like GetterSetterUtil
also do not provide the method you want.
Finally I would create a property accessor detector by myself. Maybe as a filter that I can apply on Collection
s.
Checking if the name of an IMethod matches the scheme prefix + NameOfAttribute with prefix ∈ {"get", "set"}
Also check the is
prefix in case of a boolean property and the parameter list of the method. Getters usually don't take parameters while setters usually take one parameter. I said usually, because the JavaBeans specification also allows indexed properties. E.g.
void setter(int index, PropertyType value); // indexed setter
PropertyType getter(int index); // indexed getter
void setter(PropertyType values[]); // array setter
PropertyType[] getter(); // array getter
EDIT
I added my own solution based on your proposals to my post.
Your solution might fit your requirements. Just keep in mind that a property might not have a direct backing-field. The concept of a property is a bit more abstract. I mean that if you have a property named visible
and a getter isVisible()
the class might not have a field private boolean visible
.
To make it clear you should take a look at the property rootPane
from JComponent
. It is definitely a property, because the Introspector
returns it.
BeanInfo jcomponentBeanInfo = Introspector.getBeanInfo(JComponent.class);
PropertyDescriptor[] propertyDescriptors = jcomponentBeanInfo.getPropertyDescriptors();
for (int i = 0; i < propertyDescriptors.length; i++) {
PropertyDescriptor propertyDescriptor = propertyDescriptors[i];
if("rootPane".equals(propertyDescriptor.getName())){
System.out.println("Found property rootPane");
break;
}
}
will print out
Found property rootPane
But it don't uses a direct backing-field if you take a look at the implementation.
public JRootPane getRootPane() {
return SwingUtilities.getRootPane(this);
}
and SwingUtilities.getRootPane
public static JRootPane getRootPane(Component c) {
if (c instanceof RootPaneContainer) {
return ((RootPaneContainer)c).getRootPane();
}
for( ; c != null; c = c.getParent()) {
if (c instanceof JRootPane) {
return (JRootPane)c;
}
}
return null;
}
I just want to make this more clear.