Question

I have created generic json parser using java reflection, but there is a error that i am not able to solve.

Method (at the bottom of this question), receives subclass of my custom Model class. I iterate through fields and set values from json. If subclass contains array property of some other class (which is again, subclass of Model), i've created small recursion to fill those objects.

Eg.

class UserModel extends Model
{
    @JsonResponseParam(Name="userName")
    public String Name;

    @JsonResponseParam(Name="friends")
    public FriendModel[] Friends;
}

At the end UserModel should be filled with Friends. (JsonResponseParam is custom anotation, and Name value is used as property for getting values from json)

Result of this method is IllegalArgumentException, and it is thrown on

field.set(t, values.toArray());

Here is the method:

protected <T extends Model> T getModel(T t)
{
    Field[] fields = t.getClass().getFields();

    for (Field field : fields) {
        Annotation an = field.getAnnotation(JsonResponseParam.class);

        if(an != null){
            try 
            {               
                if(field.getType() == boolean.class)                
                    field.setBoolean(t, t.getBool(((JsonResponseParam)an).Name()));

                if(field.getType() == String.class)
                    field.set(t,  t.getString(((JsonResponseParam)an).Name()));

                if(field.getType() == int.class)
                    field.setInt(t,  t.getInt(((JsonResponseParam)an).Name()));

                if(field.getType() == Date.class)
                    field.set(t,  t.getDate(((JsonResponseParam)an).Name()));

                if(field.getType().isArray()){

                    ArrayList<Model> modelArray = t.getModelArray(((JsonResponseParam)an).Name());
                    ArrayList<Model> values = new ArrayList<Model>();

                    for (Model model : modelArray) {

                        Class<? extends Model> arrayType = field.getType().getComponentType().asSubclass(Model.class);
                        Model m = arrayType.newInstance();
                        m.jsonObject = model.jsonObject;
                        model.getModel(m);
                        values.add(m);                      
                    }

                    field.set(t, values.toArray());
                }

            } catch (IllegalArgumentException e) { 
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }
    }

    return t;
}

I am suspecting on class type inconsistency between field and values..

Thank you for your time.

Was it helpful?

Solution

toArray() only return an Object[] so it cannot be assigned to any other array type.

What you want is

field.set(t, values.toArray(Array.newInstance(field.getType().getComponentType(), values.size()));

This will create an array of the type to match the field.

See Array.newInstance

OTHER TIPS

Basically, the pattern is as below:

// First, create the array
Object myArray = Array.newInstance(field.getType().getComponentType(), arraySize);

// Then, adding value to that array
for (int i = 0; i < arraySize; i++) {
    // value = ....
    Array.set(myArray, i, value);
}

// Finally, set value for that array field
set(data, fieldName, myArray);

The set function is taken from this stackoverflow question:

public static boolean set(Object object, String fieldName, Object fieldValue) {
    Class<?> clazz = object.getClass();
    while (clazz != null) {
        try {
            Field field = clazz.getDeclaredField(fieldName);
            field.setAccessible(true);
            field.set(object, fieldValue);
            return true;
        } catch (NoSuchFieldException e) {
            clazz = clazz.getSuperclass();
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }
    return false;
}

Apply the above code, we have:

if(field.getType().isArray()){
    // ....
    int arraySize = modelArray.size();
    Object values = Array.newInstance(field.getType().getComponentType(), modelArray.size());
    for (int i = 0; i < arraySize; i++) {
        // ......
        Array.set(values, i, m);                     
    }

    field.set(t, values);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top