56

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).

5
  • Have you had a look at Gson ? code.google.com/p/google-gson Commented Sep 20, 2012 at 18:32
  • Only cursory. Can it do the above? Commented Sep 20, 2012 at 18:38
  • Seems it can't, there is a Gson issue "Issue 431: Populate existing object" at code.google.com/p/google-gson/issues/detail?id=431 Commented Sep 20, 2012 at 18:44
  • ...and the "Gson RoadMap" only has "Planned Releases: Gson 2.2.3: " and empty space. Commented Sep 20, 2012 at 18:46
  • Looks at this approach stackoverflow.com/questions/55426453/… Commented Mar 30, 2019 at 16:31

7 Answers 7

98

You can do this using Jackson:

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

See also Merging Two JSON Documents Using Jackson

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, @boberj - Odd that no-one managed to find this before; the feature must've been in Jackson at the time I asked, since your link is to an older answer describing this.
But unfortunately in that case readValue will not throw exceptions if can't parse json. Is it possible revert it to normal behavior?
1

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.

2 Comments

Thanks, I'll definitely take a look! Here's their first goal, and it looks promising: Be as much extensible as possible by allowing users to add new functionnalities in a clean and easy way. Genson applies the philosophy that "We can not think of every use case, so give to users the ability to do it by them self in a easy way".
Great, I hope you will like it, in fact I am gensons author =)
0

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.)

Comments

0

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.

Comments

0

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

Comments

0

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;
}

Comments

0

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);

1 Comment

Thanks. I am afraid that this doesn't really do what I intended. This looks like 'manually' setting a field/property.

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.