Search code examples
javareflectionannotations

Pull all fields with annotation (including fields inside an object in another and fields in inner classes)


Hi I am creating a custom Excel parsing marshaller tool, you can reference this: How can I call getter/setter for property marked with custom annotation?

What I need now is to be able to find all annotations, specifically how can I find ones that nested objects or inner classes, and then call that setter/getter.

For example:

public class MyOuterClass {
    private InnerClass innerObject;

    public void setInnerObject (InnerClass innerObject) {
        this.innerObject = innerObject;
    }

    public InnerClass getInnerObject() {
        return innerObject;
    }
}

and;

public class InnerClass {

    // I need to get this field and call its setter from the class passed in, so something like:
    // MyOuterClass outClass; outClass.getInnerObject.setFieldIWant("field")
    // OR outClass.getInnerObject.getFieldIWant
    // But have to be able to do at run time, having no knowledge of the class inside
    // This must also work for a nested class

    @ExcelColumn
    private String fieldIWant;

    public void setFieldIWant(String fieldIWant) {
        this.fieldIWant = fieldIWant;
    }

    public String getFieldIWant() {
        return fieldIWant;
    }
}

Solution

  • The following classes implement the AnnotatedElement interface:

    • AccessibleObject
    • Class
    • Constructor
    • Field
    • Method
    • Package

    On object instances of said classes you can then call the:

    <object>.isAnnotationPresent(Class<? extends Annotation> annotationClass)
    

    method in which you specify the annotation you wish to check for.

    So in your case the method call for @ExcelColumn would look like:

    <object>.isAnnotationPresent(ExcelColumn.class)
    

    Then you can just use reflection to iterate over the fields/methods etc. of the object you wish to check and call .isAnnotationPresent method on each of them to check whether they have the said annotation or not.

    So if you want to do some magic on fields (and nested fields) you could create a method like so:

    public void doMagicToFields(Object someObject){
        // Get all declared fields.
        Field[] fields = someObject.getClass().getDeclaredFields();
        for(Field field: fields){
            // If the field is annotated by @ExcelColumn
            if(field.isAnnotationPresent(ExcelColumn.class){
                // If the field is a String (add more checks as needed)
                if(String.class.equals(field.getType()){
                    // Set the fields value to "myValue" in case of String.
                    field.set(someObject, "myValue");
                }
                // Recursive call to check the nested fields of this field object.
                doMagicToFields(
                    // We actually get the field object here.
                    field.get(someObject)
                );
            }
    
        }
    }