how to map a bean structure to a different schema with jax-rs
Asked Answered
L

1

1

I have this bean

@XmlRootElement
class Test {
   boolean someValue;
   List<Field> fields;
}

I would like to serialize it as

<fields>
   <field>
       <name>someValue</name>
       <value>...</value>
   </field>
</fields>
<fields>
   <field>
       <name>otherValue</name>
       <value>...</value>
   </field>
</fields>

(or as json)

How should I do that, preferrably using jaxb annotations?

I'm using jersey, but the answer doens't have to be specific to it.

Limann answered 4/5, 2011 at 9:6 Comment(5)
What type of objects are in the fields list?Tapster
Useful comment, I just edited the question to be closer to my real-world usage.Limann
My real world example is better explained in this question: #5820528Limann
Do you also need to load this structure from XML? Also what is the root element?Tapster
Yes, I also need to be able to load it. The root element can be the default one.Limann
T
1

How about the following?

Using EclipseLink JAXB (MOXy) you could do the following. Note: I'm the MOXy tech lead.

Test

import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

import org.eclipse.persistence.oxm.annotations.XmlPath;

@XmlRootElement
@XmlType(propOrder={"someValue", "fields"})
@XmlAccessorType(XmlAccessType.FIELD)
class Test {

    @XmlJavaTypeAdapter(SomeValueAdapter.class)
    @XmlPath("fields[1]")
    boolean someValue;

    @XmlJavaTypeAdapter(FieldsAdapter.class)
    List<Field> fields = new ArrayList<Field>();

    public Boolean isSomeValue() {
        return someValue;
    }

    public void setSomeValue(boolean someValue) {
        this.someValue = someValue;
    }

    public List<Field> getFields() {
        return fields;
    }

    public void setFields(List<Field> fields) {
        this.fields = fields;
    }

    public void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {
        for(Field field : fields) {
            if("someValue".equals(field.getName())) {
                someValue = Boolean.valueOf(field.getValue());
                fields.remove(field);
            }
        }
    }

}

Field

public class Field {

    private String name;
    private String value;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

}

SomeValueAdapter

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class SomeValueAdapter extends XmlAdapter<AdaptedField, Boolean> {

    @Override
    public Boolean unmarshal(AdaptedField v) throws Exception {
        String value = v.getField().getValue();
        return Boolean.valueOf(value);
    }

    @Override
    public AdaptedField marshal(Boolean v) throws Exception {
        AdaptedField adaptedField = new AdaptedField();
        Field field = new Field();
        field.setName("someValue");
        field.setValue(String.valueOf(v));
        adaptedField.setField(field);
        return adaptedField;
    }

}

FieldsAdapter

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class FieldsAdapter extends XmlAdapter<AdaptedField, Field> {

    @Override
    public Field unmarshal(AdaptedField v) throws Exception {
        return v.getField();
    }

    @Override
    public AdaptedField marshal(Field v) throws Exception {
        AdaptedField adaptedField = new AdaptedField();
        adaptedField.setField(v);
        return adaptedField;
    }

}

AdaptedField

public class AdaptedField {

    private Field field;

    public Field getField() {
        return field;
    }

    public void setField(Field field) {
        this.field = field;
    }

}

Demo

import java.io.File;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Test.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        Test test = (Test) unmarshaller.unmarshal(new File("input.xml"));

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(test, System.out);
    }

}

input.xml

<?xml version="1.0" encoding="UTF-8"?>
<test>
   <fields>
      <field>
         <name>someValue</name>
         <value>true</value>
      </field>
   </fields>
   <fields>
      <field>
         <name>otherValue</name>
         <value>1</value>
      </field>
   </fields>
   <fields>
      <field>
         <name>anotherValue</name>
         <value>2</value>
      </field>
   </fields>
</test>

For More Information

Tapster answered 4/5, 2011 at 12:54 Comment(4)
Nice to know it could be done this way. I'd really like to have no dependency (as my real problem is writing a Jira rest client with less/no dependencies). No standard way of doing this? Also, would this work with json?Limann
@Limann - You can leverage Jettison with any JAXB implementation to produce/consume JSON (bdoughan.blogspot.com/2011/04/jaxb-and-json-via-jettison.html), Jersey does this automatically for you on the server side. Using just the straight JAXNB APIs you'll probably need to create an intermediate model and convert to/from it.Tapster
I'm already using this. In fact, I used xml in this question to try to ask it differently, as my original question didn't seem to have useful answers. But I'm really using json. Can I use MOXy with json (I guess not)? Can I use MOXy for only some use, without it replacing jaxb for the rest of my app?Limann
@Limann - JAXB (JSR-222) is a spec (bdoughan.blogspot.com/2010/07/jaxb-xml-binding-standard.html), and MOXy is a JAXB implementation. MOXy like any JAXB implementation can be used with JSON via something like Jettison (bdoughan.blogspot.com/2011/04/jaxb-and-json-via-jettison.html). You have a different JAXB implementation per JAXBContext, for instructions on specifying MOXy as the JAXB provider see: bdoughan.blogspot.com/2011/05/…Tapster

© 2022 - 2024 — McMap. All rights reserved.