简体   繁体   English

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

[英]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?我想知道如何让 Jackson JSON 库将 JSON 反序列化为现有对象? 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.或者,如果不可能,我想知道是否有任何 Java JSON 反序列化库可以做到。

This seems to be a corresponding question for C#: Overlay data from JSON string to existing object instance .这似乎是 C# 的相应问题: Overlay data from JSON string to existing object instance It seems JSON.NET has a PopulateObject(string,object).似乎 JSON.NET 有一个 PopulateObject(string,object)。

You can do this using Jackson:你可以使用杰克逊做到这一点:

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

See also Merging Two JSON Documents Using Jackson另请参阅使用 Jackson 合并两个 JSON 文档

If you can use another library instead of Jackson you can try Genson http://owlike.github.io/genson/ .如果您可以使用另一个库而不是 Jackson,您可以尝试 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.除了一些其他不错的功能(例如使用没有任何注释的非空构造函数反序列化,反序列化为多态类型等)之外,它还支持将 JavaBean 反序列化为现有实例。 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 .如果您有任何问题,请随时使用其邮件列表http://groups.google.com/group/genson

If you are using spring framework you can use BeanUtils library for this task.如果您使用的是 spring 框架,则可以将 BeanUtils 库用于此任务。 First deserialize your json String normally and then use BeanUtils to set this object inside a parent object.首先正常反序列化您的 json 字符串,然后使用 BeanUtils 在父对象中设置此对象。 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);

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.) (所以不是真正的答案。我希望有更好的答案,只是想避免其他人以这种方式回答。)

flexJson can also help you do the same. flexJson 也可以帮助您做到这一点。

Here is an example copied from FlexJson Doc这是从FlexJson Doc复制的示例

The deserializeInto function takes your string and reference to existing object. 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);

Note that the reference returned in p is same as charlieClone just with updated values.请注意, p 中返回的引用与 charlieClone 相同,只是具有更新的值。

I used Jackson + Spring's DataBinder to accomplish something like this.我使用 Jackson + Spring 的 DataBinder 来完成这样的事情。 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);
}

could always load into a dummy object and use reflection to transfer the data.总是可以加载到一个虚拟对象中并使用反射来传输数据。 if your heart is set on just using gson如果您只使用 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;
}

You can use my repositories :).您可以使用我的存储库:)。

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
}

this way, JSON will parse values to the map it finds in the buffer.这样,JSON 会将值解析为它在缓冲区中找到的映射。 And if the map contains a list and the JSON value also has a list.如果地图包含一个列表并且 JSON 值也有一个列表。 The list on the map will not be replaced.地图上的列表不会被替换。 instead, it will be used to contain the values.相反,它将用于包含值。

If you used Bean.forInstance(yo) the returned remote map will have some additional features.如果您使用Bean.forInstance(yo)则返回的远程地图将具有一些附加功能。

repositories:存储库:

util repo (required): github.com/cufyorg/util util repo(必需): github.com/cufyorg/util

base repo (required): github.com/cufyorg/base基础github.com/cufyorg/base (必需): github.com/cufyorg/base

JSON repo (required): github.com/cufyorg/json JSON 存储库(必需): github.com/cufyorg/json

beans repo (optional): github.com/cufyorg/beans bean 存储库(可选): github.com/cufyorg/beans

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM