-1

Based on the question Get all Fields of class hierarchy I want to ask the following using -as I suppose- reflection. Lets suppose I have the following Class

package com.foo.bar

public class Employee{ 

    private String firstName; 

    private String id; 

    private Address address; 

// Getters and Setters follow

}

and the Class Address is

package com.foo.bar

public class Address{ 

    private String street; 

    private String streetNum; 

// Getters and Setters follow

}

I want to populate a list with all fields from all classes originating from Employee in the form

  • Employee.firstName
  • Employee.id
  • Employee.Address.street
  • Employee.Address.streetNum

All the classes I am interested in are either in the same package as Employee class ex com.foo.bar or in specific packages that I am already aware of.

My original thinking is to somehow get all the fields, get the packages from the class of the fields and somehow drill down in multiple levels to get the information I need.

Any help is greatly appreciated.

Thanks

ps. I am using JDK 7

Alexius DIAKOGIANNIS
  • 2,465
  • 2
  • 21
  • 32

2 Answers2

2

Here's a simple way that inspects class declared fields:

static Set<Field> getFields(Class<?> cls) {
    Set<Field> set = new HashSet<>();

    for (Field f : cls.getDeclaredFields()) {
        set.add(f);

        //a filter to avoid standard classes. Update accordingly
        if (f.getType().getName().startsWith("com.foo.bar")) {
            set.addAll(getFields(f.getType()));
        }
    }

    return set;
}

And a simple call:

public static void main(String[] args) {
    Set<Field> all = getFields(Employee.class);
    for (Field f : all) {
        System.out.println(String.format("%s.%s", 
             f.getDeclaringClass().getSimpleName(), f.getName()));
    }
}

With your example classes, the above prints:

Employee.firstName
Employee.address
Address.street
Address.streetNum
Employee.id

And here's an equivalent Java8+ version (only inspecting 2 levels of the tree):

Stream.of(Employee.class.getDeclaredFields())
        .flatMap(f -> Stream.concat(Stream.of(f), 
                Stream.of(f.getType().getDeclaredFields())))
        .filter(f -> f.getDeclaringClass()
                      .getPackage()
                      .getName()
                      .startsWith("com.foo.bar"))
        .map(f -> String.format("%s.%s", 
                    f.getDeclaringClass().getSimpleName(), f.getName()))
        .forEach(System.out::println);

The filter above is used to limit inspected classes to those in the current package (change accordingly). Without it, one gets String's fields, etc.

You may also want to call distinct() to remove duplicates if they may show up.

ernest_k
  • 44,416
  • 5
  • 53
  • 99
1

Thank you all, I created a recursive function that does the trick. The function is the following

private void getClassFields(final Class c,final List<String> fields) throws ClassNotFoundException {
    for(Field f : c.getDeclaredFields()){
        if(f.getType().getName().contains("foo.bar")){
            getClassFields(Class.forName(f.getType().getName()),fields);
        }else {
            fields.add(f.getName());
        }
    }
}
Alexius DIAKOGIANNIS
  • 2,465
  • 2
  • 21
  • 32