Generating getters and setters

Let's assume that Melon has three fields (type, weight, and ripe) and defines only a getter for type and a setter for ripe:

public class Melon {

private String type;
private int weight;
private boolean ripe;
...

public String getType() {
return type;
}

public void setRipe(boolean ripe) {
this.ripe = ripe;
}
...
}

In order to generate the missing getters and setters, we start by identifying them. The following solution loops the declared fields of the given class and assumes that a foo field doesn't have a getter if the following apply:

  • There is no get/isFoo() method
  • The return type is not the same as the field type
  • The number of arguments is not 0

For each missing getter, this solution adds in a map an entry containing the field name and type:

private static Map<String, Class<?>> 
fetchMissingGetters(Class<?> clazz) {

Map<String, Class<?>> getters = new HashMap<>();
Field[] fields = clazz.getDeclaredFields();
String[] names = new String[fields.length];
Class<?>[] types = new Class<?>[fields.length];

Arrays.setAll(names, i -> fields[i].getName());
Arrays.setAll(types, i -> fields[i].getType());

for (int i = 0; i < names.length; i++) {
String getterAccessor = fetchIsOrGet(names[i], types[i]);

try {
Method getter = clazz.getDeclaredMethod(getterAccessor);
Class<?> returnType = getter.getReturnType();

if (!returnType.equals(types[i]) ||
getter.getParameterCount() != 0) {
getters.put(names[i], types[i]);
}
} catch (NoSuchMethodException ex) {
getters.put(names[i], types[i]);
// log exception
}
}

return getters;
}

Further, the solution loops the declared fields of the given class and assume that a foo field doesn't have a setter if the following apply:

  • The field is not final
  • There is no setFoo() method
  • The method returns void
  • The method has a single parameter
  • The parameter type is the same as the field type
  • If the parameter name is present, it should be the same as the name of the field

For each missing setter, this solution adds an entry containing the field name and type in a map:

private static Map<String, Class<?>> 
fetchMissingSetters(Class<?> clazz) {

Map<String, Class<?>> setters = new HashMap<>();
Field[] fields = clazz.getDeclaredFields();
String[] names = new String[fields.length];
Class<?>[] types = new Class<?>[fields.length];

Arrays.setAll(names, i -> fields[i].getName());
Arrays.setAll(types, i -> fields[i].getType());

for (int i = 0; i < names.length; i++) {
Field field = fields[i];
boolean finalField = !Modifier.isFinal(field.getModifiers());

if (finalField) {
String setterAccessor = fetchSet(names[i]);

try {
Method setter = clazz.getDeclaredMethod(
setterAccessor, types[i]);

if (setter.getParameterCount() != 1 ||
!setter.getReturnType().equals(void.class)) {

setters.put(names[i], types[i]);
continue;
}

Parameter parameter = setter.getParameters()[0];
if ((parameter.isNamePresent() &&
!parameter.getName().equals(names[i])) ||
!parameter.getType().equals(types[i])) {
setters.put(names[i], types[i]);
}
} catch (NoSuchMethodException ex) {
setters.put(names[i], types[i]);
// log exception
}
}
}

return setters;
}

Well, so far, we know what fields don't have getters and setters. Their names and types are stored in a map. Let's loop the map and generate the getters:

public static StringBuilder generateGetters(Class<?> clazz) {

StringBuilder getterBuilder = new StringBuilder();
Map<String, Class<?>> accessors = fetchMissingGetters(clazz);

for (Entry<String, Class<?>> accessor: accessors.entrySet()) {
Class<?> type = accessor.getValue();
String field = accessor.getKey();
String getter = fetchIsOrGet(field, type);

getterBuilder.append(" public ")
.append(type.getSimpleName()).append(" ")
.append(getter)
.append("() { ")
.append(" return ")
.append(field)
.append("; ")
.append("} ");
}

return getterBuilder;
}

And let's generate the setters:

public static StringBuilder generateSetters(Class<?> clazz) {

StringBuilder setterBuilder = new StringBuilder();
Map<String, Class<?>> accessors = fetchMissingSetters(clazz);

for (Entry<String, Class<?>> accessor: accessors.entrySet()) {
Class<?> type = accessor.getValue();
String field = accessor.getKey();
String setter = fetchSet(field);

setterBuilder.append(" public void ")
.append(setter)
.append("(").append(type.getSimpleName()).append(" ")
.append(field).append(") { ")
.append(" this.")
.append(field).append(" = ")
.append(field)
.append("; ")
.append("} ");
}

return setterBuilder;
}

The preceding solution relies on three simple helpers listed in the following. The code is straightforward:

private static String fetchIsOrGet(String name, Class<?> type) {
return "boolean".equalsIgnoreCase(type.getSimpleName()) ?
"is" + uppercase(name) : "get" + uppercase(name);
}

private static String fetchSet(String name) {
return "set" + uppercase(name);
}

private static String uppercase(String name) {
return name.substring(0, 1).toUpperCase() + name.substring(1);
}

Now, let's call it for the Melon class:

Class<?> clazz = Melon.class;
StringBuilder getters = generateGetters(clazz);
StringBuilder setters = generateSetters(clazz);

The output will reveal the following generated getters and setters:

public int getWeight() {
return weight;
}

public boolean isRipe() {
return ripe;
}

public void setWeight(int weight) {
this.weight = weight;
}

public void setType(String type) {
this.type = type;
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.205.99