obj = obj.getClass().getSuperclass().cast(obj);
This line does not do what you expect it to do. Casting an Object does not actually change it, it just tells the compiler to treat it as something else.
E.g. you can cast a List to a Collection, but it will still remain a List.
However, looping up through the super classes to access fields works fine without casting:
Class<?> current = yourClass;
while(current.getSuperclass()!=null){ // we don't want to process Object.class
// do something with current's fields
current = current.getSuperclass();
}
BTW, if you have access to the Spring Framework, there is a handy method for looping through the fields of a class and all super classes:
ReflectionUtils.doWithFields(baseClass, FieldCallback)
(also see this previous answer of mine: Access to private inherited fields via reflection in Java)
obj = obj.getClass().getSuperclass().cast(obj);
This line does not do what you expect it to do. Casting an Object does not actually change it, it just tells the compiler to treat it as something else.
E.g. you can cast a List to a Collection, but it will still remain a List.
However, looping up through the super classes to access fields works fine without casting:
Class<?> current = yourClass;
while(current.getSuperclass()!=null){ // we don't want to process Object.class
// do something with current's fields
current = current.getSuperclass();
}
BTW, if you have access to the Spring Framework, there is a handy method for looping through the fields of a class and all super classes:
ReflectionUtils.doWithFields(baseClass, FieldCallback)
(also see this previous answer of mine: Access to private inherited fields via reflection in Java)
getDeclaredFields() gives you all fields on that Class, including private ones.
getFields() gives you all public fields on that Class AND it's superclasses.
If you want private / protected methods of Super Classes, you will have to repeatedly call getSuperclass() and then call getDeclaredFields() on the Super Class object.
Nothing here isn't clearly explained in the javadocs
Try the following:
Field[] fields = c.getClass().getFields();
If you want all superclass fields, see the following:
Retrieving the inherited attribute names/values using Java Reflection
Your C class does not extend any class. Then, getDeclaredFields() only returns String filedC as you have seen. You cannot do c.fieldA="TestA" and c.fieldB="TestB" because your class does not declare this fields. Anyway, in case of C extends B and B extends A, method getFields() returns only public fields (including inherited):
Returns an array containing Field objects reflecting all the accessible public fields of the class or interface represented by this Class object.
And getDeclaredFields() returns all fields declared in the class (not including inherited):
Returns an array of Field objects reflecting all the fields declared by the class or interface represented by this Class object. This includes public, protected, default (package) access, and private fields, but excludes inherited fields.
You can do it like this. You need to add more condition as per your requirement in filter:
public static List<Field> getAllFields(List<Field> fields, Class<?> type) {
fields.addAll(
Arrays.stream(type.getDeclaredFields())
.filter(field -> field.isAnnotationPresent(NotNull.class))
.collect(Collectors.toList())
);
if (type.getSuperclass() != null) {
getAllFields(fields, type.getSuperclass());
}
return fields;
}
Call example:
List<Field> fieldList = new ArrayList<>();
getAllFields(fieldList,B.class);
You can use the "reflections" library.
https://github.com/ronmamo/reflections
Reflections reflections = new Reflections(
new ConfigurationBuilder()
.setUrls(ClasspathHelper.forPackage("your.packageName"))
.setScanners(new SubTypesScanner(), new TypeAnnotationsScanner(), new FieldAnnotationsScanner()));
Set<Field> fields =
reflections.getFieldsAnnotatedWith(YourAnnotation.class);
fields.stream().forEach(field -> {
System.out.println(field.getDeclaringClass());
System.out.println(field.getName());
});
Field[] fields = YourClassName.class.getFields();
returns an array of all public variables of the class.
getFields() return the fields in the whole class-heirarcy. If you want to have the fields defined only in the class in question, and not its superclasses, use getDeclaredFields(), and filter the public ones with the following Modifier approach:
Modifier.isPublic(field.getModifiers());
The YourClassName.class literal actually represents an object of type java.lang.Class. Check its docs for more interesting reflection methods.
The Field class above is java.lang.reflect.Field. You may take a look at the whole java.lang.reflect package.
https://docs.oracle.com/javase/tutorial/reflect/class/classMembers.html also has charts for locating methods and constructors.

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