3

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;
    }
}
buræquete
  • 14,226
  • 4
  • 44
  • 89
CodyK
  • 3,426
  • 4
  • 36
  • 52
  • 1
    possible duplicate of http://stackoverflow.com/questions/2237289/is-there-a-more-efficient-way-to-get-an-annotated-method – durron597 Apr 17 '15 at 13:55

2 Answers2

6

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)
            );
        }

    }
}
Ceiling Gecko
  • 3,104
  • 2
  • 24
  • 33
  • 1
    This helped me a lot just now, but I have one correction: To check if a field is a String what you want is String.class.equals(field.getType()) rather than String.class.equals(field.getClass()). The getClass method returns the class of the Field instance, i.e. it's always java.lang.reflect.Field. – themik81 Jun 24 '19 at 10:14
1

To find inner classes MyOuterClass.class.getClasses() will get you started, but will only give you one level of visibility. You'll need to iterate through those inner classes (e.g., SomeInnerClass.class.getClasses()) to check if they have an inner class themselves.

Once you have your list of classes it's as simple as SomeClass.class.getMethods() to get a list of all methods.

for(Class<?> clazz : OuterClass.class.getClasses()) {
        for(Method method : clazz.getMethods()) {
            if(method.getAnnotation(ExcelColumn.class) != null) {
                System.out.println(clazz.getName() + "." + method.getName());
            }
        }
    }
davegarred
  • 36
  • 4
  • Thanks, I figured thats what I needed to do, but in order to call the setter or getter I will also have to build the string for PropertyUtils.getNestedProperty(Object, String) PropertyUtils.setNestedProperty(Object, String, Object) dynamically. http://commons.apache.org/proper/commons-beanutils/javadocs/v1.9.2/apidocs/org/apache/commons/beanutils/package-summary.html#standard.nested – CodyK Apr 17 '15 at 14:40
  • Ah, yeah that's a bit trickier and best left to an external package. I wasn't sure what part you were stuck on here. – davegarred Apr 17 '15 at 20:30
  • Thanks, yea I basically created a recursive method to pull all the fields I wanted, thanks for your help. – CodyK Apr 20 '15 at 12:51