Read embedded object in Jackson

I'm trying to read a legacy JSON code using Jackson 2.0-RC3, however I'm stuck with an "embedded" object.

Given a following JSON:

{
    "title": "Hello world!",
    "date": "2012-02-02 12:23:34".
    "author": "username",
    "author_avatar": "http://.../",
    "author_group": 123,
    "author_prop": "value"
}

How can I map it into the following structure:

class Author {
    @JsonPropery("author")
    private String name;

    @JsonPropery("author_avatar")
    private URL avatar;

    @JsonProperty("author_group")
    private Integer group;

    ...
}

class Item {
    private String title;

    @JsonProperty("date")
    private Date createdAt;

    // How to map this?
    private Author author;
}

I was trying to do that with @JsonDeserialize but it seems that I'd have to map the entire Item object that way.

Answers


To deal with an "embedded" object you should use @JsonUnwrapped — it's an equivalent of the Hibernate's @Embeddable/@Embedded.

class Item {
    private String title;

    @JsonProperty("date")
    private Date createdAt;

    // How to map this?
    @JsonUnwrapped
    private Author author;
}

I would deserialize the original JSON to a single, flat object first (kind of like an adapter), then create your own domain objects.

class ItemLegacy {
    private String title;

    @JsonProperty("date")
    private Date createdAt;

    @JsonPropery("author")
    private String name;

    @JsonPropery("author_avatar")
    private URL avatar;

    @JsonProperty("author_group")
    private Integer group;

    @JsonProperty("author_prop")
    private Integer group;
}

Then use this object to fill out your Item and Author objects and create the correct relationships.

 //... the deserialized original JSON
 ItemLegacy legacy ...

 // create an author
 Author author = new Author();
 author.setName(legacy.getName());
 author.setGroup(legacy.getGroup());
 ...

 // create an item
 Item item = new Item();
 item.setTitle(legacy.getTitle());
 ...

 // finally set the author... and you should have the desired structure
 item.setAuthor(author);

Your Item class could only be automatically deserialized from the following form:

{
    "title": "Hello world!",
    "date": "2012-02-02 12:23:34".
    "author": { 
                "name": "username", 
                "author_avatar": "http://...", 
                "author_group": "123", 
                "author_prop": "value" 
              }
}

You might be able to do something with custom deserialization, but it would not be the simpler solution for sure.


Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.

I'm not sure if Jackson supports this use case, but below is an example of how you can leverage MOXy's @XmlPath extension to meet your requirements. Note you will need to use an EclipseLink 2.4.0 nightly label from April 7, 2012 or newer.

Item

The author property on Item is mapped with @XmlPath('.'). This means that the content of Author is pulled up to the same level as the content for Item. I also needed to use an XmlAdapter for the Date property as the format you are using doesn't match MOXy's default representation.

package forum10036530;

import java.util.Date;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.eclipse.persistence.oxm.annotations.XmlPath;

@XmlAccessorType(XmlAccessType.FIELD)
class Item {
    private String title;

    @XmlElement(name="date")
    @XmlJavaTypeAdapter(DateAdapter.class)
    private Date createdAt;

    @XmlPath(".")
    private Author author;
}

Author

package forum10036530;

import java.net.URL;
import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
class Author {
    @XmlElement(name="author")
    private String name;

    @XmlElement(name="author_avatar")
    private URL avatar;

    @XmlElement(name="author_group")
    private Integer group;

    @XmlElement(name="author_prop")
    private String prop;
}

DateAdapter

package forum10036530;

import java.text.SimpleDateFormat;
import java.util.Date;
import javax.xml.bind.annotation.adapters.XmlAdapter;

public class DateAdapter extends XmlAdapter<String, Date> {

    private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

    @Override
    public Date unmarshal(String string) throws Exception {
        return dateFormat.parse(string);
    }

    @Override
    public String marshal(Date date) throws Exception {
        return dateFormat.format(date);
    }

}

jaxb.properties

A file called jaxb.properties with the following entry must be placed in the same package as the domain classes to specify MOXy as the JAXB (JSR-222) provider.

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

input.json/Output

{
   "title" : "Hello world!",
   "date" : "2012-02-02 12:23:34",
   "author" : "username",
   "author_avatar" : "http://www.example.com/foo.png",
   "author_group" : 123,
   "author_prop" : "value"
}

For More Information


Need Your Help

How to get the body element using jquery

javascript jquery html

I want to get the body element of an html using jquery and then disable the vertical scrolling?

How do I obtain a crash dump

c# debugging

I need to get a crash dump from a program. How do i get it?