I have a JSON like this
JSON是这样的
{ "id":1, "name":"Jack", "parent.id":2 }
Note the dot on "parent.id" property
注意“父”上的点。id”属性
Is it possible to map those JSON to the following classes ?
是否可以将这些JSON映射到以下类?
class Child {
private int id;
private String name;
private Parent parent;
//getter and setter methods
}
class Parent {
private int id;
private String name;
//getter and setter methods
}
So the mapping result would be similar to following statements:
因此,映射结果将类似于以下语句:
Parent parent = new Parent();
parent.setId(2);
Child child = new Child();
child.setId(1);
child.setName("Jack");
child.setParent(parent); // Here is the result
1 个解决方案
#1
13
you can convert this
你可以把这
{ "id":1, "name":"Jack", "parent.id":2 }
into this
到这个
{ "id":1, "name":"Jack", "parent": { "id":2 } }
by using this
通过使用这个
// I'm using jQuery here
$.fn.serializeObject = function() {
var arrayData, objectData;
arrayData = this.serializeArray();
objectData = {};
$.each(arrayData, function() {
var value;
if (this.value != null) {
value = this.value;
} else {
value = '';
}
// search for "parent.id" like attribute
if (this.name.indexOf('.') != -1) {
var attrs = this.name.split('.');
var tx = objectData;
for (var i = 0; i < attrs.length - 1; i++) {
if (objectData[attrs[i]] == undefined)
objectData[attrs[i]] = {};
tx = objectData[attrs[i]];
}
tx[attrs[attrs.length - 1]] = value;
} else {
if (objectData[this.name] != null) {
if (!objectData[this.name].push) {
objectData[this.name] = [objectData[this.name]];
}
objectData[this.name].push(value);
} else {
objectData[this.name] = value;
}
}
});
return objectData;
};
and then you can serialize your code by using JSON.serialize()
.
然后可以使用JSON.serialize()序列化代码。
if you are using Jackson, then you can deserialize the JSON request string by doing any of these:
如果您正在使用Jackson,那么您可以通过以下操作来反序列化JSON请求字符串:
1. create a custom Jackson deserialize module
1。创建自定义Jackson反序列化模块
2. parse the JSON yourself
2。解析JSON自己
public Child parseJackson(String jsonRequest) {
// what we need
ObjectMapper mapper;
JsonNode root, parentNode;
// your models
Child child;
Parent parent;
// assign
mapper = new ObjectMapper();
root = mapper.readTree(jsonRequest); // deserialize JSON as tree
parentNode = root.get("parent"); // get the "parent" branch
// assign (again)
child = mapper.readValue(root, Child.class);
parent = mapper.readValue(parentNode, Parent.class);
child.setParent(parent);
return child;
}
the downside of this method is you have to parse for every single JsonRequest with nested objects and it will be messy when there's a complex nested structure. If this is a problem, I suggest you do the #3
这种方法的缺点是必须对每个带有嵌套对象的JsonRequest进行解析,如果有一个复杂的嵌套结构,就会很混乱。如果这是一个问题,我建议你做#3
3. create a custom Jackson ObjectMapper class to automate this process
3所示。创建一个定制的Jackson ObjectMapper类来自动化这个过程。
The idea is to build generic process for #2 so that it could handle any nested request.
其思想是为#2构建通用流程,以便它能够处理任何嵌套的请求。
public class CustomObjectMapper extends ObjectMapper {
// here's the method you need
@Override
public <T> T readValue(String src, Class<T> type)
throws IOException, JsonParseException, JsonMappingException {
JsonNode root = this.readTree(src);
try {
return readNestedValue(root, type);
} catch (InstantiationException | IllegalAccessException | IOException
| IllegalArgumentException | InvocationTargetException e) {
return super.readValue(src, type);
}
}
// if you're using Spring, I suggest you implement this method as well
// since Spring's MappingJacksonHttpMessageConverter class will call
// this method.
@Override
public <T> T readValue(InputStream src, JavaType type)
throws IOException, JsonParseException, JsonMappingException {
JsonNode root = this.readTree(src);
try {
return readNestedValue(root, (Class<T>) type.getRawClass());
} catch (InstantiationException | IllegalAccessException | IOException
| IllegalArgumentException | InvocationTargetException e) {
return super.readValue(src, type);
}
}
// we need this to recursively scan the tree node
protected <T> T readNestedValue(JsonNode root, Class<T> type)
throws InstantiationException, IllegalAccessException, IOException,
IllegalArgumentException, InvocationTargetException {
// initialize the object use ObjectMapper's readValue
T obj = super.readValue(root, type);
Iterator it = root.getFieldNames();
while (it.hasNext()) {
String name = (String) it.next();
String camelCaseName = name.substring(0, 1).toUpperCase() + name.substring(1);
JsonNode node = root.get(name);
Field f;
try {
f = type.getDeclaredField(name);
} catch (NoSuchFieldException e) {
f = findFieldInSuperClass(name, type.getSuperclass());
}
// if no field found then ignore
if (f == null) continue;
Method getter, setter;
try {
getter = type.getMethod("get" + camelCaseName);
} catch (NoSuchMethodException e) {
getter = findGetterInSuperClass("get" + camelCaseName, type.getSuperclass());
}
// if no getter found or it has been assigned then ignore
if (getter == null || getter.invoke(obj) != null) continue;
try {
setter = type.getMethod("set" + camelCaseName);
} catch (NoSuchMethodException ex) {
setter = findSetterInSuperClass("set" + camelCaseName, type.getSuperclass(), f.getType());
}
// if no setter found then ignore
if (setter == null) continue;
setter.invoke(obj, readNestedValue(node, f.getType()));
}
return obj;
}
// we need this to search for field in super class
// since type.getDeclaredField() will only return fields that in the class
// but not super class
protected Field findFieldInSuperClass(String name, Class sClass) {
if (sClass == null) return null;
try {
Field f = sClass.getDeclaredField(name);
return f;
} catch (NoSuchFieldException e) {
return findFieldInSuperClass(name, sClass.getSuperclass());
}
}
protected Method findGetterInSuperClass(String name, Class sClass) {
if (sClass == null) return null;
try {
Method m = sClass.getMethod(name);
return m;
} catch (NoSuchMethodException e) {
return findGetterInSuperClass(name, sClass.getSuperclass());
}
}
protected Method findSetterInSuperClass(String name, Class sClass, Class type) {
if (sClass == null) return null;
try {
Method m = sClass.getMethod(name, type);
return m;
} catch (NoSuchMethodException e) {
return findSetterInSuperClass(name, sClass.getSuperclass(), type);
}
}
}
If you're using Spring, then the final step is registering this class as Spring bean.
如果您正在使用Spring,那么最后一步是将这个类注册为Spring bean。
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper">
<bean class="x.y.z.CustomObjectMapper"/>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
with these set up you can easily use
有了这些设置,你可以很容易地使用。
@RequestMapping("/saveChild.json")
@ResponseBody
public Child saveChild(@RequestBody Child child) {
// do something with child
return child;
}
Hope this helps :)
希望这有助于:)
#1
13
you can convert this
你可以把这
{ "id":1, "name":"Jack", "parent.id":2 }
into this
到这个
{ "id":1, "name":"Jack", "parent": { "id":2 } }
by using this
通过使用这个
// I'm using jQuery here
$.fn.serializeObject = function() {
var arrayData, objectData;
arrayData = this.serializeArray();
objectData = {};
$.each(arrayData, function() {
var value;
if (this.value != null) {
value = this.value;
} else {
value = '';
}
// search for "parent.id" like attribute
if (this.name.indexOf('.') != -1) {
var attrs = this.name.split('.');
var tx = objectData;
for (var i = 0; i < attrs.length - 1; i++) {
if (objectData[attrs[i]] == undefined)
objectData[attrs[i]] = {};
tx = objectData[attrs[i]];
}
tx[attrs[attrs.length - 1]] = value;
} else {
if (objectData[this.name] != null) {
if (!objectData[this.name].push) {
objectData[this.name] = [objectData[this.name]];
}
objectData[this.name].push(value);
} else {
objectData[this.name] = value;
}
}
});
return objectData;
};
and then you can serialize your code by using JSON.serialize()
.
然后可以使用JSON.serialize()序列化代码。
if you are using Jackson, then you can deserialize the JSON request string by doing any of these:
如果您正在使用Jackson,那么您可以通过以下操作来反序列化JSON请求字符串:
1. create a custom Jackson deserialize module
1。创建自定义Jackson反序列化模块
2. parse the JSON yourself
2。解析JSON自己
public Child parseJackson(String jsonRequest) {
// what we need
ObjectMapper mapper;
JsonNode root, parentNode;
// your models
Child child;
Parent parent;
// assign
mapper = new ObjectMapper();
root = mapper.readTree(jsonRequest); // deserialize JSON as tree
parentNode = root.get("parent"); // get the "parent" branch
// assign (again)
child = mapper.readValue(root, Child.class);
parent = mapper.readValue(parentNode, Parent.class);
child.setParent(parent);
return child;
}
the downside of this method is you have to parse for every single JsonRequest with nested objects and it will be messy when there's a complex nested structure. If this is a problem, I suggest you do the #3
这种方法的缺点是必须对每个带有嵌套对象的JsonRequest进行解析,如果有一个复杂的嵌套结构,就会很混乱。如果这是一个问题,我建议你做#3
3. create a custom Jackson ObjectMapper class to automate this process
3所示。创建一个定制的Jackson ObjectMapper类来自动化这个过程。
The idea is to build generic process for #2 so that it could handle any nested request.
其思想是为#2构建通用流程,以便它能够处理任何嵌套的请求。
public class CustomObjectMapper extends ObjectMapper {
// here's the method you need
@Override
public <T> T readValue(String src, Class<T> type)
throws IOException, JsonParseException, JsonMappingException {
JsonNode root = this.readTree(src);
try {
return readNestedValue(root, type);
} catch (InstantiationException | IllegalAccessException | IOException
| IllegalArgumentException | InvocationTargetException e) {
return super.readValue(src, type);
}
}
// if you're using Spring, I suggest you implement this method as well
// since Spring's MappingJacksonHttpMessageConverter class will call
// this method.
@Override
public <T> T readValue(InputStream src, JavaType type)
throws IOException, JsonParseException, JsonMappingException {
JsonNode root = this.readTree(src);
try {
return readNestedValue(root, (Class<T>) type.getRawClass());
} catch (InstantiationException | IllegalAccessException | IOException
| IllegalArgumentException | InvocationTargetException e) {
return super.readValue(src, type);
}
}
// we need this to recursively scan the tree node
protected <T> T readNestedValue(JsonNode root, Class<T> type)
throws InstantiationException, IllegalAccessException, IOException,
IllegalArgumentException, InvocationTargetException {
// initialize the object use ObjectMapper's readValue
T obj = super.readValue(root, type);
Iterator it = root.getFieldNames();
while (it.hasNext()) {
String name = (String) it.next();
String camelCaseName = name.substring(0, 1).toUpperCase() + name.substring(1);
JsonNode node = root.get(name);
Field f;
try {
f = type.getDeclaredField(name);
} catch (NoSuchFieldException e) {
f = findFieldInSuperClass(name, type.getSuperclass());
}
// if no field found then ignore
if (f == null) continue;
Method getter, setter;
try {
getter = type.getMethod("get" + camelCaseName);
} catch (NoSuchMethodException e) {
getter = findGetterInSuperClass("get" + camelCaseName, type.getSuperclass());
}
// if no getter found or it has been assigned then ignore
if (getter == null || getter.invoke(obj) != null) continue;
try {
setter = type.getMethod("set" + camelCaseName);
} catch (NoSuchMethodException ex) {
setter = findSetterInSuperClass("set" + camelCaseName, type.getSuperclass(), f.getType());
}
// if no setter found then ignore
if (setter == null) continue;
setter.invoke(obj, readNestedValue(node, f.getType()));
}
return obj;
}
// we need this to search for field in super class
// since type.getDeclaredField() will only return fields that in the class
// but not super class
protected Field findFieldInSuperClass(String name, Class sClass) {
if (sClass == null) return null;
try {
Field f = sClass.getDeclaredField(name);
return f;
} catch (NoSuchFieldException e) {
return findFieldInSuperClass(name, sClass.getSuperclass());
}
}
protected Method findGetterInSuperClass(String name, Class sClass) {
if (sClass == null) return null;
try {
Method m = sClass.getMethod(name);
return m;
} catch (NoSuchMethodException e) {
return findGetterInSuperClass(name, sClass.getSuperclass());
}
}
protected Method findSetterInSuperClass(String name, Class sClass, Class type) {
if (sClass == null) return null;
try {
Method m = sClass.getMethod(name, type);
return m;
} catch (NoSuchMethodException e) {
return findSetterInSuperClass(name, sClass.getSuperclass(), type);
}
}
}
If you're using Spring, then the final step is registering this class as Spring bean.
如果您正在使用Spring,那么最后一步是将这个类注册为Spring bean。
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper">
<bean class="x.y.z.CustomObjectMapper"/>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
with these set up you can easily use
有了这些设置,你可以很容易地使用。
@RequestMapping("/saveChild.json")
@ResponseBody
public Child saveChild(@RequestBody Child child) {
// do something with child
return child;
}
Hope this helps :)
希望这有助于:)