将JSON反序列化为现有对象(Java)

时间:2012-09-20 18:25:20

标签: java json jackson deserialization

我想知道如何让Jackson JSON库将JSON反序列化为现有对象?我试图找到如何做到这一点;但它似乎只能采取一个类并自己实例化它。

或者如果不可能,我想知道是否有任何Java JSON反序列化库可以做到这一点。

这似乎是C#的相应问题:Overlay data from JSON string to existing object instance。看来JSON.NET有一个PopulateObject(字符串,对象)。

7 个答案:

答案 0 :(得分:58)

你可以用杰克逊做到这一点:

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

另见Merging Two JSON Documents Using Jackson

答案 1 :(得分:1)

如果您可以使用其他图书馆代替杰克逊,您可以尝试Genson http://owlike.github.io/genson/。除了一些其他好的功能(例如使用非空构造函数反序列化而没有任何注释,反序列化为多态类型等),它还支持将JavaBean反序列化为现有实例。这是一个例子:

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

如果您有任何疑问,请不要犹豫使用其邮件列表http://groups.google.com/group/genson

答案 2 :(得分:1)

如果您使用的是spring框架,则可以使用BeanUtils库执行此任务。首先正常反序列化您的json String,然后使用BeanUtils在父对象中设置此对象。它还希望在父对象中设置对象的变量名。 以下是代码段:

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

答案 3 :(得分:0)

flexJson也可以帮助你做同样的事情。

以下是从FlexJson Doc

复制的示例

deserializeInto函数接受您的字符串和对现有对象的引用。

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

请注意,p中返回的引用与charlieClone相同,只是更新了值。

答案 4 :(得分:0)

我使用Jackson + Spring的DataBinder来完成这样的事情。此代码处理数组但不处理嵌套对象。

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

答案 5 :(得分:0)

总是可以加载到虚拟对象中并使用反射来传输数据。如果你的心脏只是使用gson

例子。 假设此代码位于您要将数据复制到

中的对象中
    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;
}

答案 6 :(得分:0)

您可以使用我的存储库:)。

Object yo = //yourObject
String js = //json source

Map remote = Object$.remoteMap(yo, false); //or you can use Bean.forInstance(yo);
Reader reader = new StringReader(js);//you can replace this with any reader :)
AtomicReference buffer = new AtomicReference(remote);

try {
    JSON.global.parse(buffer, reader, null, null);
} catch (IOException ignored) {
    //If any exception got thrown by the reader
}

这样,JSON会将值解析到它在缓冲区中找到的映射。并且如果地图包含一个列表,并且JSON值也包含一个列表。地图上的列表将不会被替换。相反,它将用于包含值。

如果您使用Bean.forInstance(yo),则返回的远程地图将具有一些其他功能。

存储库:

实用程序回购(必填):github.com/cufyorg/util

基本仓库(必填):github.com/cufyorg/base

JSON存储库(必填):github.com/cufyorg/json

beans回购(可选):github.com/cufyorg/beans