loop through field’s values (or methods) of an object in java

I have a class called Material and some subclasses of it: Book, Audio, magazine… I also have an ArrayList<Material> arrayOfMaterials

I am trying to implement a search method: I want to give a string to this method as a parameter and it should call all the getters() in every object inside the array, plus the toString functions and compare the results to the input parameter.

I have read about Reflection in java, but if I got it right, that will give me the names of the fields or methods of a class, but won’t give me the values of those fields in objects or the results of calling its getters().

I need to loop through ALL getters, or through all fields (I shouldn’t access fields from outside, but it’d work), and not all subclasses of Materialhave the same number of fields.

Is there any way to do this? I have no code to paste because, as far as I know, there is no way to do this.

Answer

The following example retrieves the field names of the concrete class (declaredField = fields declared by the class, (public)field = public fields declared by the class and it’s super classes), derives a name of a corresponding getter from it (i.e. private String example -> getExample), searches for the method with the same name and invokes it on the instance m of Material

Material m = ...;
Stream.of(Material.class.getDeclaredFields())
      .map(field -> "get" + ucFirst(field.getName()))
      .map(getterName -> Material.class.getMethod(getterName))
      .map(getterMethod -> getterMethod.invoke(m))
      .forEach(fieldValue -> {
            //do something
      });

...
private String ucFirst(String input) {
    if(input.length() <= 1){
        return input.toUpperCase();
    }
    return input.substring(0, 1).toUpperCase() + input.substring(1);
}

(I removed the exception handling for better readability)

This is just one way to do it, there are many others. The same way you could access the toString method:

String toString = (String)Material.class.getMethod("toString").invoke(m);

Or you could get all the getter you want:

Stream.of(Material.class.getMethods())
      .filter(method -> method.getName().startsWith("get"))
      .map(getterMethod -> getterMethod.invoke(m))
      .forEach(fieldValue -> {
            //do something
      });

Note that getMethods will retrieve only public methods, but from all the super classes as well, while getDeclaredMethods will retrieve only method from the current classes. This may be important to know when dealing with the subclasses.

Leave a Reply

Your email address will not be published. Required fields are marked *