Jonas N
Jonas N

Reputation: 1777

Deserialize JSON into existing object (Java)

I'd like to know how one might get the Jackson JSON library to deserialize JSON into an existing object? I've tried to find how to to this; but it seems to only be able to take a Class and instantiate it itself.

Or if not possible, I'd like to know if any Java JSON deserialization libraries can do it.

This seems to be a corresponding question for C#: Overlay data from JSON string to existing object instance. It seems JSON.NET has a PopulateObject(string,object).

Upvotes: 55

Views: 26131

Answers (7)

yokesh sharma
yokesh sharma

Reputation: 49

If you are using spring framework you can use BeanUtils library for this task. First deserialize your json String normally and then use BeanUtils to set this object inside a parent object. It also expects the variable name of the object to be set inside the parent object. Here is the code snippet:

childObject = gson.fromJson("your json string",class.forName(argType))
BeanUtils.setProperty(mainObject, "childObjectName", childObject);

Upvotes: 0

Jordan Haynes
Jordan Haynes

Reputation: 9

could always load into a dummy object and use reflection to transfer the data. if your heart is set on just using gson

example. assuming this code is in the object you want to copy data into

    public void loadObject(){
Gson gson = new Gson();
//make temp object
YourObject tempStorage = (YourObject) gson.fromJson(new FileReader(theJsonFile), YourObject.class);
//get the fields for that class
ArrayList<Field> tempFields = new ArrayList<Field>();
ArrayList<Field> ourFields = new ArrayList<Field>();
getAllFields(tempFields, tempStorage.getClass());
getAllFields(thisObjectsFields, this.getClass());
for(Field f1 : tempFields){
    for(Field f2 : thisObjectsFields){
        //find matching fields
        if(f1.getName().equals(f2.getName()) && f1.getType().equals(f2.getType())){
            //transient and statics dont get serialized and deserialized.
            if(!Modifier.isTransient(f1.getModifiers())&&!Modifier.isStatic(f1.getModifiers())){
                //make sure its a loadable thing
                f2.set(this, f1.get(tempStorage));
            }
        }
    }
}

}

public static List<Field> getAllFields(List<Field> fields, Class<?> type) {
    for (Field field : type.getDeclaredFields()) {
        fields.add(field);
    }
    if (type.getSuperclass() != null) {
        fields = getAllFields(fields, type.getSuperclass());
    }
    return fields;
}

Upvotes: 0

eugen
eugen

Reputation: 5916

If you can use another library instead of Jackson you can try Genson http://owlike.github.io/genson/. In addition of some other nice features (such as deserialize using a non empty constructor without any annotation, deserialize to polymorphic types, etc) it supports deserialization of JavaBean into an existing instance. Here is an example:

BeanDescriptorProvider provider = new Genson().getBeanDescriptorFactory();
BeanDescriptor<MyClass> descriptor = provider.provide(MyClass.class, genson);
ObjectReader reader = new JsonReader(jsonString);
MyClass existingObject = descriptor.deserialize(existingObject, reader, new Context(genson));

If you have any question don't hesitate to use its mailing list http://groups.google.com/group/genson.

Upvotes: 1

Johan Boberg
Johan Boberg

Reputation: 3781

You can do this using Jackson:

mapper.readerForUpdating(object).readValue(json);

See also Merging Two JSON Documents Using Jackson

Upvotes: 96

splashout
splashout

Reputation: 553

I used Jackson + Spring's DataBinder to accomplish something like this. This code handles arrays but not nested objects.

private void bindJSONToObject(Object obj, String json) throws IOException, JsonProcessingException {
    MutablePropertyValues mpv = new MutablePropertyValues();
    JsonNode rootNode = new ObjectMapper().readTree(json);
    for (Iterator<Entry<String, JsonNode>> iter = rootNode.getFields(); iter.hasNext(); ) {
        Entry<String, JsonNode> entry = iter.next();
        String name = entry.getKey();
        JsonNode node = entry.getValue();
        if (node.isArray()) {
            List<String> values = new ArrayList<String>();
            for (JsonNode elem : node) {
                values.add(elem.getTextValue());
            }
            mpv.addPropertyValue(name, values);
            if (logger.isDebugEnabled()) {
                logger.debug(name + "=" + ArrayUtils.toString(values));
            }
        }
        else {
            mpv.addPropertyValue(name, node.getTextValue());
            if (logger.isDebugEnabled()) {
                logger.debug(name + "=" + node.getTextValue());
            }
        } 
    }
    DataBinder dataBinder = new DataBinder(obj);
    dataBinder.bind(mpv);
}

Upvotes: 0

faizan
faizan

Reputation: 690

flexJson can also help you do the same.

Here is an example copied from FlexJson Doc

The deserializeInto function takes your string and reference to existing object.

 Person charlie = new Person("Charlie", "Hubbard", cal.getTime(), home, work );
 Person charlieClone = new Person( "Chauncy", "Beauregard", null, null, null );
 Phone fakePhone = new Phone( PhoneNumberType.MOBILE, "303 555 1234");
 charlieClone.getPhones().add( fakePhone ); 
 String json = new JSONSerializer().include("hobbies").exclude("firstname", "lastname").serialize( charlie ); 
 Person p = new JSONDeserializer<Person>().deserializeInto(json, charlieClone);

Note that the reference returned in p is same as charlieClone just with updated values.

Upvotes: 0

Jonas N
Jonas N

Reputation: 1777

One solution is to parse a new object graph/tree and then unify-copy into the existing object graph/tree. But that's of course less efficient, and more work, especially if concrete types differ because of less availability of type information. (So not really an answer. I hope there's a better answer, just want to avoid others answering in this way.)

Upvotes: 0

Related Questions