我正在使用spring 3.1.2,我需要将一个json对象解析为POJO。 这是我需要解析的json:
{
"Person" : {
"id" : "2"
},
"Dog" : {
"dateOfBirth" : "2012-08-20 00:00:00",
"price" : "10.00"
}
}
我需要将这个json对象(由两个对象组合)转换为一个POJO,这里是:
public class MyClass{
public MyClass(){}
public MyClass(String personsId, TimeStamp dogsDateOfBirth, BigDecimal dogsPrice){
.... // assign each parameter to the appropriate field
}
private String personsId;
private TimeStamp dogsDateOfBirth;
private BigDecimal dogsPrice;
//... Getters and Setters for each field
}
就此而言,我使用了ObjectMapper mapper = new ObjectMapper();
现在因为我有几个json对象,我的代码看起来像这样:
String json = ... ;// A json with several objects as above
JsonNode tree = mapper.readTree(json);
Iterator<JsonNode> iter = tree.path("data").getElements();
while (iter.hasNext()){
JsonNode node = iter.next();
MyClass myClass = mapper.readValue(node, MyClass.class);
... // do something with myClass object
}
当我运行时 - 我得到以下异常:
org.codehaus.jackson.map.JsonMappingException: No suitable constructor found for type [simple type, class ...MyClass]: can not instantiate from JSON object (need to add/enable type information?)
我尝试创建一个简单的POJO - Person
:
public class Person{
private String id;
public Person(){}
public Person(String id){
this.id = id;
}
... // Getter and Setter
}
并执行以下操作:
Person person = mapper.readValue(node.path("Person"), Person.class);
我得到了这个(相同)例外:
org.codehaus.jackson.map.JsonMappingException: No suitable constructor found for type [simple type, class ...Person]: can not instantiate from JSON object (need to add/enable type information?)
我试着阅读一些有关type information的内容 - 但无法理解它对我的帮助。
如何将此json转换为我的POJO?
感谢。
答案 0 :(得分:6)
我做的是这样的: 我创建了一个包含Person对象和Dog对象的新类,这些类需要是静态的(我发现它here)。 以下是课程:
public static class MyNewClass{
private Person person;
private Dog dog;
... // two constructors and getters and setters
public static class Person{
private String id;
... // two constructors and getters and setters
}
public static class Dog{
private String dateOfBirth;
private String price;
... // two constructors and getters and setters
}
}
现在我的代码看起来像这样:
JsonNode tree = mapper.readTree(jsonString);
Iterator<JsonNode> iter = tree.path("data").getElements();
while (iter.hasNext()){
JsonNode node = iter.next();
Person person = mapper.readValue(node.path("Person"), Person.class);
Dog dog = mapper.readValue(node.path("Dog"), Dog.class);
MyNewClass myNewClass = new MyNewClass(person , dog);
... //Do something with it
}
我仍然希望在不创建这两个对象(人和狗)的情况下这样做 - 现在已经足够了 - 但如果有人有想法 - 我想在这里!
感谢。
答案 1 :(得分:4)
问题与此处描述的相同:Jackson error: no suitable constructor
您尝试实例化的类不是静态的。因此,它有一个隐藏的构造函数参数。这导致杰克逊失败。
答案 2 :(得分:1)
尝试更改MyClass的构造函数以接受所有字段的String
,因为所有字段都是JSON数据中的字符串。顺便说一下,JSON中没有TimeStamps的标准表示,所以无论如何你都需要对日期字段进行转换。对于“价格”字段,您可以尝试更改
"price" : "10.00"
到
"price" : 10.00
在JSON数据中;应该允许它被读作BigDecimal。
答案 3 :(得分:1)
如果你想将你的两个json对象组合成一个java对象,这里有一个Genson库http://code.google.com/p/genson/的解决方案。 可以缩短以下代码并使用Gensons标准转换器,但作为示例将不太清楚。这里的优点是您直接使用流式api,因此非常快。
class MyClassConverter implements Deserializer<MyClass> {
@Override
public MyClass deserialize(ObjectReader reader, Context ctx)
throws TransformationException, IOException {
reader.beginObject();
MyClass myClass = new MyClass();
for (; reader.hasNext();) {
reader.next();
if ("Person".equals(reader.name())) {
readPerson(reader, myClass);
} else if ("Dog".equals(reader.name())) {
readDog(reader, myClass);
}
}
reader.endObject();
return myClass;
}
private void readPerson(ObjectReader reader, MyClass myClass) throws IOException {
reader.beginObject();
for (; reader.hasNext();) {
reader.next();
if ("id".equals(reader.name()))
myClass.setPersonsId(reader.valueAsString());
}
reader.endObject();
}
private void readDog(ObjectReader reader, MyClass myClass) throws IOException {
reader.beginObject();
for (; reader.hasNext();) {
reader.next();
if ("dateOfBirth".equals(reader.name()))
myClass.setDogsDateOfBirth(Timestamp.valueOf(reader.valueAsString()));
else if ("price".equals(reader.name()))
myClass.setDogsPrice(new BigDecimal(reader.valueAsString()));
}
reader.endObject();
}
}
如果您想要将Person和Dog作为分隔对象的其他示例,您可以在Gensons用户组上询问。
希望这有帮助!
修改强> 这是另一个版本更短更好但未包含在发布的0.91版本中(我今天可能会发布新版本,因为我是作者:)) 为了使它工作,你必须使用@JsonProperty(the_name_from_json)注释你的getter(以及你也进行序列化的setter)。请注意,Genson不需要任何getter / setter,如果你想它只能使用字段(默认情况下它使用getter / setter,如果可用,否则为字段)。
Genson genson = new Genson.Builder().withDeserializerFactory(new MyClassConverterFactory()).create();
MyClass myClass = genson.deserialize(json, MyClass.class);
public static class MyClassConverterFactory implements Factory<Deserializer<MyClass>> {
@SuppressWarnings("unchecked")
@Override
public Deserializer<MyClass> create(Type type, Genson genson) {
BeanDescriptor<MyClass> myClassDescriptor = (BeanDescriptor<MyClass>) genson.getBeanDescriptorFactory().provide(MyClass.class, genson);
return new MyClassConverter(myClassDescriptor);
}
}
public static class MyClassConverter implements Deserializer<MyClass> {
BeanDescriptor<MyClass> myClassDescriptor;
public MyClassConverter(BeanDescriptor<MyClass> myClassDescriptor) {
this.myClassDescriptor = myClassDescriptor;
}
@Override
public MyClass deserialize(ObjectReader reader, Context ctx)
throws TransformationException, IOException {
reader.beginObject();
MyClass myClass = new MyClass();
for (; reader.hasNext();) {
reader.next();
if ("Person".equals(reader.name())) {
myClassDescriptor.deserialize(myClass, reader, ctx);
} else if ("Dog".equals(reader.name())) {
myClassDescriptor.deserialize(myClass, reader, ctx);
}
}
reader.endObject();
return myClass;
}
}
答案 4 :(得分:1)
注意:我是EclipseLink JAXB (MOXy)主管,是JAXB (JSR-222)专家组的成员。
您可以利用MOXy中基于路径的映射来支持您的用例。
<强> MyClass的强>
@XmlPath
注释用于指定基于路径的映射:
package forum12139380;
import java.math.BigDecimal;
import java.sql.Timestamp;
import org.eclipse.persistence.oxm.annotations.XmlPath;
import javax.xml.bind.annotation.*;
@XmlAccessorType(XmlAccessType.FIELD)
public class MyClass {
public MyClass() {
}
public MyClass(String personsId, Timestamp dogsDateOfBirth,
BigDecimal dogsPrice) {
this.personsId = personsId;
this.dogsDateOfBirth = dogsDateOfBirth;
this.dogsPrice = dogsPrice;
}
@XmlPath("Person/id/text()")
private String personsId;
@XmlPath("Dog/dateOfBirth/text()")
private Timestamp dogsDateOfBirth;
@XmlPath("Dog/price/text()")
@XmlSchemaType(name="string")
private BigDecimal dogsPrice;
// ... Getters and Setters for each field
}
<强> jaxb.properties 强>
要将MOXy指定为JAXB提供程序,您需要在与域模型相同的程序包中包含名为jaxb.properties
的文件,并带有以下条目:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
<强>演示强>
下面的代码会将JSON转换为对象,然后再转换回JSON。
package forum12139380;
import java.util.*;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.persistence.jaxb.JAXBContextProperties;
public class Demo {
public static void main(String[] args) throws Exception {
Map<String, Object> properties = new HashMap<String, Object>(2);
properties.put(JAXBContextProperties.MEDIA_TYPE, "application/json");
properties.put(JAXBContextProperties.JSON_INCLUDE_ROOT, false);
JAXBContext jc = JAXBContext.newInstance(new Class[] {MyClass.class}, properties);
Unmarshaller unmarshaller = jc.createUnmarshaller();
StreamSource json = new StreamSource("src/forum12139380/input.json");
MyClass myClass = (MyClass) unmarshaller.unmarshal(json, MyClass.class).getValue();
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(myClass, System.out);
}
}
<强> input.xml中/输出强>
以下是运行演示代码的输入和输出。在我的例子中,我正在使用MOXy的默认表示Timestamp
。您可以使用XmlAdapter
轻松控制此表示形式(请参阅:jaxb unmarshal timestamp)。
{
"Person" : {
"id" : "2"
},
"Dog" : {
"dateOfBirth" : "2012-08-20T00:00:00.0",
"price" : "10.00"
}
}
答案 5 :(得分:1)
所有这些答案都意味着使用POJO是唯一的方法。显然,在一个Web项目中,就像一个Spring Web服务项目一样,拥有POJO是很重要的,但只是单元测试你不能只使用一个通用的Jackson JsonNode对象吗?
你不能简单地使用Jackson ObjectMapper反序列化为JsonNode而不使用POJO类吗? JsonNode的实例本身是否有资格成为合法的Jackson POJO?我确定它确实如此,因为一旦你有一个JsonNode实例,你可以在json中获取对象:
node.get(0).get(1).get("nodename").asText();