How to convert json to POJO in java using jackson

I am using spring 3.1.2 and I need to parse a json object in POJO. This is the json I need to parse:

{ "Person" : { "id" : "2" }, "Dog" : { "dateOfBirth" : "2012-08-20 00:00:00", "price" : "10.00" } } 

I need to convert this json object (which is combined from two objects) into one POJO, here it is:

 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 } 

In this regard, I used ObjectMapper mapper = new ObjectMapper(); Now, since I have several json objects, my code looks like this:

  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 } 

When I run this, I get the following exception:

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

I tried to create a simple POJO - Person :

 public class Person{ private String id; public Person(){} public Person(String id){ this.id = id; } ... // Getter and Setter } 

and follow these steps:

 Person person = mapper.readValue(node.path("Person"), Person.class); 

I get this (same) exception:

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

I tried to read some information about - but could not figure out how this could help me.

How can I convert this json to my POJO?

Thanks.

+8
java json spring jackson pojo
source share
6 answers

I did the following: I created a new class that contains a Person object and a Dog object, these classes should be static (I found here here ). Here are the classes:

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

Now my code is as follows:

  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 } 

I still want to do this without creating these two objects (Person and Dog). This is good enough, but if anyone has an idea, I would love to be here!

Thanks.

+5
source share

The problem is the same as described here: Jackson error: no suitable constructor

The class you are trying to create is not static. Because of this, it has a hidden constructor. This makes Jackson fail.

+4
source share

Try modifying the MyClass constructor to accept a String for all fields, since all fields are strings in your JSON data. By the way, there is no standard representation for TimeStamps in JSON, so in any case, you will need to convert date fields. In the field "price" you can try to change

 "price" : "10.00" 

to

 "price" : 10.00 

in JSON data; which should allow it to be read as BigDecimal.

+1
source share

If you want to combine two json objects into one java object, this is a solution with the Genson library http://code.google.com/p/genson/ . The following code can be shortened and use standard Gensons converters, but this will be less clear as an example. The advantage is that you use streaming api directly, so it is very fast.

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

If you need other examples in which you have Person and Dog as separate objects, you can request from the Gensons user group.

Hope this helps!

EDIT Here is another version, shorter and more pleasant, but not contained in the released version 0.91 (I will probably release a new version today, as I am the author :)) To make it work, you will need to annotate your recipients (and setters if you are also doing serialization) with @JsonProperty (the_name_from_json). Note that Genson does not need any getter / setter if you want it to be able to use only fields (by default it uses getter / setter if the field is otherwise available).

 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; } } 
+1
source share

Note. I have EclipseLink JAXB (MOXy) leads and a member of the JAXB Group (JSR-222) .

You can use route-based mapping in MOXy to support your use case.

Myclass

The @XmlPath annotation @XmlPath used to specify route-based matching:

 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

To specify MOXy as the JAXB provider, you need to include a file named jaxb.properties in the same package as your domain model, with the following entry:

 javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory 

Demo

The code below converts JSON to objects and then back to 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 / output

The following is the entry and exit from running the demo code. In my example, I am using MOXy default indent from Timestamp . You can easily manage this view with the XmlAdapter (see jaxb unmarshal timestamp ).

 { "Person" : { "id" : "2" }, "Dog" : { "dateOfBirth" : "2012-08-20T00:00:00.0", "price" : "10.00" } } 
+1
source share

All of these answers imply that using POJO is the only way to do this. Obviously, in a web project, such as the Spring web services project, it is important to have a POJO, but just for unit tests, could you just use a common Jackson JsonNode object?

Can't you just de-serialize in JsonNode using Jackson ObjectMapper without using the POJO class? Is a JsonNode instance legal Jackson POJO in itself? I am sure this is happening, because as soon as you have an instance of JsonNode, you can get the objects in json:

 node.get(0).get(1).get("nodename").asText(); 
+1
source share

All Articles