我想知道如何让 Jackson JSON 库将 JSON 反序列化为现有对象?我试图找到如何做到这一点;但它似乎只能接受一个类并自己实例化它。
或者如果不可能,我想知道是否有任何 Java JSON 反序列化库可以做到这一点。
这似乎是 C# 的相应问题:Overlay data from JSON string to existing object instance。JSON.NET 似乎有一个 PopulateObject(string,object)。
我想知道如何让 Jackson JSON 库将 JSON 反序列化为现有对象?我试图找到如何做到这一点;但它似乎只能接受一个类并自己实例化它。
或者如果不可能,我想知道是否有任何 Java JSON 反序列化库可以做到这一点。
这似乎是 C# 的相应问题:Overlay data from JSON string to existing object instance。JSON.NET 似乎有一个 PopulateObject(string,object)。
如果您可以使用另一个库而不是 Jackson,您可以尝试 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。
如果您使用的是 spring 框架,您可以使用 BeanUtils 库来完成此任务。首先正常反序列化您的 json 字符串,然后使用 BeanUtils 将此对象设置在父对象中。它还期望在父对象内设置对象的变量名。这是代码片段:
childObject = gson.fromJson("your json string",class.forName(argType))
BeanUtils.setProperty(mainObject, "childObjectName", childObject);
我使用 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);
}
一种解决方案是解析一个新的对象图/树,然后统一复制到现有的对象图/树中。但这当然效率较低,工作量更大,尤其是在具体类型因类型信息可用性较低而不同的情况下。(所以不是真正的答案。希望有更好的答案,只是想避免其他人以这种方式回答。)
flexJson 也可以帮助你做同样的事情。
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 相同,只是具有更新的值。
总是可以加载到一个虚拟对象中并使用反射来传输数据。如果您一心只想使用 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;
}
您可以使用我的存储库:)。
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
豆回购(可选):github.com/cufyorg/beans