'Iterating through multiple subclasses and attempting to get the value of each field. java.lang.IllegalArgumentException: Can't set XXX field XX to XXX

I am trying to iterate through every subclass of a class and get the value of every field for each of them. I have successfully gotten every subclass with a ClassPathScanningCandidateComponentProvider object and can also look at every field.

This works as expected:

try {
        ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(
                false);
        provider.addIncludeFilter(new AssignableTypeFilter(Resource.class));

        Set<BeanDefinition> components = 
      provider.findCandidateComponents("com/availaboard/engine/resource");
        for (BeanDefinition component : components) {
            Class<?> cls = Class.forName(component.getBeanClassName());
            System.out.println("Class: " + cls);
            for (Field field : cls.getDeclaredFields()) {
                field.setAccessible(true);
                System.out.println("Field: " + field);
                System.out.println("Field Type: " + field.getType());
            }
        }

Output:

Class: class com.availaboard.engine.resource.Equipment
Class: class com.availaboard.engine.resource.Resource
Field: private java.lang.String com.availaboard.engine.resource.Resource.name
Field Type: class java.lang.String
Field: private com.availaboard.engine.resource.Status com.availaboard.engine.resource.Resource.status
Field Type: class com.availaboard.engine.resource.Status
Field: private int com.availaboard.engine.resource.Resource.id
Field Type: int
Class: class com.availaboard.engine.resource.Room
Class: class com.availaboard.engine.resource.User
Field: private java.lang.String com.availaboard.engine.resource.User.firstName
Field Type: class java.lang.String
Field: private java.lang.String com.availaboard.engine.resource.User.lastName
Field Type: class java.lang.String
Field: private java.lang.String com.availaboard.engine.resource.User.email
Field Type: class java.lang.String
Field: private java.lang.String com.availaboard.engine.resource.User.username
Field Type: class java.lang.String
Field: private java.lang.String com.availaboard.engine.resource.User.password
Field Type: class java.lang.String

The problem is when I try to get the value of a field. Since none of the fields are set it should return null. field.get(field.getType()) But instead now the program throws an error.

Class: class com.availaboard.engine.resource.Equipment
Class: class com.availaboard.engine.resource.Resource
Field: private java.lang.String com.availaboard.engine.resource.Resource.name
Field Type: class java.lang.String
java.lang.IllegalArgumentException: Can not set java.lang.String field com.availaboard.engine.resource.Resource.name to java.lang.Class
    at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
    at java.base/jdk.internal.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)

The error occurs right after it get's the first field of the Resource object because that is the first Object that has fields.

I have also tried passing the class in to the field.get() method: field.get(cls) But it still gives the same exception. Thoughts?



Solution 1:[1]

For those of you in the future who need help here’s my answer:

public <E extends Resource> void printClass(int ID, Class<E> type) {
    try {
        Resource res = (Resource) Class.forName(type.getName()).getConstructor().newInstance();
        for (Field field : res.getClass().getDeclaredFields()) {
            field.setAccessible(true);
            System.out.println("Field: " + field);
            System.out.println("Field Type: " + field.getType());

            field.set(res, "test");
            System.out.println("Field Value: " + field.get(res));
        }
}

I basically just created a new instance of the class with class.forName and set it to the superclass of the class it has to come from, Resource

Solution 2:[2]

What I understood is you are trying to set a String while setting the parameter, but the column is of type Resource. field (reference variable) is a field of class Resource. Therefore, it can only get the fields from objects that are instances of Resource or subclasses. The object you're trying to get the field from is a Class object. Replace that cls with an instance of Resource and it'll work.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Sam
Solution 2 Bohemian