6

Iam currently trying to create a distinct List<Class> classList which contains all Classes of an object for example

DemoObject.java

public class DemoObject {

    private Integer id;
    private String name;
    private BigDecimal price;
    private Boolean isActive;
    private List<NestedDemoObject> nested;
}

NestedDemoObject.java

public class NestedDemoObject {

    private Integer id;
    private String nameNest;
    private Boolean isActive;
}

What i want to create is a method public List<Class> getDistinctClasses(Class cl); which you give as input for example DemoObject.class and returns a list with

[DemoObject.class, Integer.class, String.class, BigDecimal.class, Boolean.class, List.class, NestedDemoObject.class]

Another example for NestedDemoObject.class would be

[NestedDemoObject.class, Integer.class, String.class, Boolean.class]

I tried to use the .getDeclaredClasses() from Class without any luck. There is any way to get all nested classes from an object with Reflection API?

Any help or direction appreciated.

6
  • I believe what you're looking for are the classes of the Fields, correct? Commented Nov 1, 2018 at 8:26
  • yes correct, iam looking to get all distinct classes of the fields including the root object class (changed my examples post to include and the root object class) Commented Nov 1, 2018 at 8:28
  • @ohlec tryied Mark's solution with getDeclaredFields() and works great but as you said its impossible to get NestedDemoObject this way. there is any possible workaround for this ? Commented Nov 1, 2018 at 8:49
  • @ohlec Actually you're not right. The fields DO KNOW their own generic types. Please check my answer in a separate post. Commented Nov 1, 2018 at 10:02
  • @ETO indeed, thanks for that. I'll delete my comments to keep this concise. Commented Nov 1, 2018 at 10:15

2 Answers 2

3

The solution provided by Mark is partially correct. You're on the right way trying to retrieve the classes from declared fields. However getType() method does not reveal the generic types.

In order to access the generic types you should use Field.getGenericType() instead. It returns the classes as Type objects. The Field objects DO KNOW their own types (they are not erased as one may believe mistakenly). This is a java 1.8+ example printing the types with generics:

Arrays.stream(DemoObject.class.getDeclaredFields())
            .map(Field::getGenericType)
            .map(Type::getTypeName)
            .distinct()
            .forEach(System.out::println);

It will print the following result:

java.lang.Integer
java.lang.String
java.math.BigDecimal
java.lang.Boolean
java.util.List<com.eto.sandbox.NestedDemoObject>

If you want to play with generic types or parse them for any reason then you could use this example:

 Arrays.stream(DemoObject.class.getDeclaredFields())
            .map(Field::getGenericType)
            .distinct()
            .forEach(type -> {
                if (type instanceof Class) {
                    // This is a simple class
                } else if (type instanceof ParameterizedType) {
                    // This is a generic type. You can parse its parameters recursively.
                }
            });
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for the answer im going to test it. I think something like this could work
@PanosK, you're welcome! Feel free to ask questions if any.
BTW, take a look at ParameterizedType.getActualTypeArguments() method. It extracts generic sub-types.
Note that this information about generic types might be not present at runtime - but this is pretty much edge case, like some obfuscated code. As this information is just not required for JVM, so it can be stripped, but it is included by default. So in most cases solution like this is perfect.
3

Maybe this points you in the right direction:

for (Field f : DemoObject.class.getDeclaredFields()) {
    System.out.println(f.getType().getName());
}

This prints:

java.lang.Integer
java.lang.String
java.math.BigDecimal
java.lang.Boolean
java.util.List

You can get a class instance through something like Class.forName.

I find it odd that getDeclaredClasses is not working for me either, and I will look into that. I'll update the answer when I know more.

UPDATE

getDeclaredClasses prints classes defined inside a class like so:

class DemoObject {

    private Integer id;
    private String name;
    private BigDecimal price;
    private Boolean isActive;
    private List<NestedDemoObject> nested;

    public class InnerClass {

    }
}

Then executing getDeclaredClasses:

for (Class<?> f : DemoObject.class.getDeclaredClasses()) {
    System.out.println(f.getName());
}

prints the value:

DemoObject$InnerClass

2 Comments

@PanosK I have updated my answer, figured out how getDeclaredClasses actually works.
ok thanks a lot for the help , so i have to go with getDeclaredFields() and somehow get the type of NestedDemoObject declared on List

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.