Reputation: 1093
I'm trying to write a code which can take either XML or JSON input and output JSON or XML respectively. I.e, if I give XML it should give back JSON, and if I give JSON it should give XML output.
I was told this is possible using Jackson API and JAXB Annotations. Can anyone help me out with this?
Upvotes: 2
Views: 31586
Reputation: 116522
Sure, but don't think of it as converting between XML and JSON -- this is pretty much the wrong thing to do, causing compatibility issues -- but that of converting Java Objects (POJOs) to/from JSON and XML. You can use one or two tools for this: one common combination is to use Jackson for JSON, and JAXB for XML, to use their respective strengths.
It is also possible to use a single tool; Blaise explained how JAXB implementations can help. Similarly, you can use Jackson for both: for XML part you need to use Jackson XML module. With Jackson, you can use Jackson's own annotations (prefered), or JAXB annotations for compatibility; both work for XML and JSON use cases.
Use of XML module with Jackson does not differ a lot from default JSON processing, except that you will need XmlMapper
sub-class of ObjectMapper
.
If using this from JAX-RS (like Jersey), you can use Jackson JAX-RS XML provider.
Upvotes: 1
Reputation: 149017
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
Below is an example of how you can use MOXy's JSON-binding to support this use case.
JAVA MODEL
Below is an example domain model annotated with JAXB metadata. The same metadata will be used for both the object-to-XML and object-to-JSON conversions.
Customer
import java.util.List;
import javax.xml.bind.annotation.*;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer {
private int id;
private String firstName;
@XmlElement(nillable=true)
private String lastName;
private List<PhoneNumber> phoneNumbers;
}
PhoneNumber
import javax.xml.bind.annotation.*;
@XmlAccessorType(XmlAccessType.FIELD)
public class PhoneNumber {
@XmlAttribute
private String type;
@XmlValue
private String number;
}
XML INPUT
Below is the XML input that we will use. Note how the xsi:nil
attribute is used on the lastName
element to indicate a null
value. Also note how the phoneNumbers
element has a type
attribute.
<?xml version="1.0" encoding="UTF-8"?>
<customer>
<id>123</id>
<firstName>Jane</firstName>
<lastName xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<phoneNumbers type="work">555-1111</phoneNumbers>
</customer>
DEMO CODE
jaxb.properties
To specify MOXy as your JAXB provider you need to include a file called jaxb.properties
in the same package as your domain model with the following entry (see: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html):
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Demo
The following demo code will convert the XML to the domain model and then back to JSON.
import java.io.File;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.MarshallerProperties;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Customer.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum14734741/input.xml");
Customer customer = (Customer) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(MarshallerProperties.MEDIA_TYPE, "application/json");
marshaller.setProperty(MarshallerProperties.JSON_INCLUDE_ROOT, false);
marshaller.marshal(customer, System.out);
}
}
JSON OUTPUT
Note how the null
value for the lastName
key is represented as proper JSON. Also note how the type
key doesn't contain any special indicator corresponding to it being an XML attribute in the XML representation.
{
"id" : 123,
"firstName" : "Jane",
"lastName" : null,
"phoneNumbers" : [ {
"type" : "work",
"value" : "555-1111"
} ]
}
Upvotes: 11