ymajoros ymajoros - 1 year ago 113
reST (reStructuredText) Question

how to use some indirection when unmarshalling json to java bean using Jersey using jaxb annotations

I'm trying to unmarshall some received json (from Jira restful web service).

Problem is: an "issue" has a "summary" property and a list of fields.

Summary is not present as an attribute in the received json, but as a value of the "fields" attribute. I insist on unmarshalling to this structure:

class Issue {
String summary;
List<Field> fields;
// getters/setters and lots of other fields

Received JSON:

"value":"test 1234"

I don't want to use Jira's own client (too many dependencies which I don't want in my app).

edit: I asked my question another way to try to make it clear: how to map a bean structure to a different schema with jax-rs

Answer Source

Your annotated class should be bijective: it should allow to generate the same input from which it was unmarshalled. If you still want to use a non-bijective object graph, you can use @XmlAnyElement the following way:

public class Issue {

    @XmlElement(required = true)
    protected Fields fields;

    public Fields getFields() {
        return fields;

In the input you gave, fields is not a list, but a field (JSON uses [] to delimit lists):

public class Fields {

    @XmlElement(required = true)
    protected Summary summary;

    private List<Element> fields;

    public List<Element> getFields() {
        return fields;

    public Summary getSummary() {
        return summary;

In order to catch Summary, you'll have to define a dedicated class. Remaining fields will be grouped in the fields list of elements.

public class Summary {

    protected String name;

    public String getName() {
        return name;

Below, a unit test using your input shows that everything work:

public class JaxbTest {
    public void unmarshal() throws JAXBException, IOException {
        URL xmlUrl = Resources.getResource("json.txt");
        InputStream stream = Resources.newInputStreamSupplier(xmlUrl).getInput();
        Issue issue = parse(stream, Issue.class);

        assertEquals("summary", issue.getFields().getSummary().getName());

        Element element = issue.getFields().getFields().get(0);
        assertEquals("customfield_10080", element.getTagName());
        assertEquals("name", element.getFirstChild().getLocalName());
        assertEquals("Testeur", element.getFirstChild().getFirstChild().getTextContent());

    private <T> T parse(InputStream stream, Class<T> clazz) throws JAXBException {
        JSONUnmarshaller unmarshaller = JsonContextNatural().createJSONUnmarshaller();
        return unmarshaller.unmarshalFromJSON(stream, clazz);

    private JSONJAXBContext JsonContextNatural() throws JAXBException {
        return new JSONJAXBContext(JSONConfiguration.natural().build(), Issue.class);

This tests shows that without using dedicated classes, your code will quickly be hard to read.

You will need those maven dependencies to run it:

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download