3

I have to use a lib that only gives me a JAXBContext to marshall and unmarshall XML data to Java objects. Also I don't ever see XML: Only the JAXB objects are passed to me. What I now need is a conversion of those objects not to XML, but to JSON.

Is there a way to create a marshaller from the given JAXBContext that can be used to generate JSON output?

The situation is that I'm not only transforming data. I also have logic that acts on the Java objects between XML and JSON (and manipulates the data). Also it's a two-way transformation. The JAXBContext is the information I have about the transformation between XML and Java objects - My intention was to reuse this context information for not having to implement a second transformation with a second technology different to JAXB. The JAXBContext (and its Java objects) already have the information about the XML structure; The automated recognition of that structure by JAXB is the time-saving reason for using it.

Sebastian Barth
  • 4,079
  • 7
  • 40
  • 59
  • How try with transforming first XML and then to Json like [XML to Json](http://stackoverflow.com/questions/1823264/quickest-way-to-convert-xml-to-json-in-java/1823328#1823328) ??? Or may need to implement suitable xml parser to transform xml content to requried Json format !! – Wundwin Born Sep 26 '14 at 15:45
  • The problem is that I'm not only transforming data. I also have logic that have to act on the Java objects between XML and JSON. Also it's a two-way transformation. The JAXBContext is the information I have about the transformation between XML and Java objects - My intention was to reuse that context information to not having to implement a second transformation with a second technology different to JAXB. The JAXBContext (and its Java objects) already have the information about the XML structure; The automated recognition of that structure by JAXB is the time-saving reason for using it. – Sebastian Barth Sep 28 '14 at 12:26
  • Also I don't ever see XML. Only the JAXB objects are passed to me. (Added this to the question) – Sebastian Barth Sep 28 '14 at 12:32

1 Answers1

1

If your JAXB classes just use the basic annotations, you can take a look at JacksonJAXBAnnotations, allows Jackson mapper to recognize JAXN annotations. Four lines of code (in the simplest marshalling case) would be all you would need.

ObjectMapper mapper = new ObjectMapper();
JaxbAnnotationModule module = new JaxbAnnotationModule();
mapper.registerModule(module);
mapper.writeValue(System.out, yourJaxbObject);

You can see the link above for all the supported annotations. The maven artifact you'll need is

<dependency>
    <groupId>com.fasterxml.jackson.module</groupId>
    <artifactId>jackson-module-jaxb-annotations</artifactId>
    <version>2.4.0</version>
</dependency>
  • See the github for jackson-module-jaxb-annotations - Note this artifact has dependencies on jackson-core and jackson-databind. So if you're not using maven, then you will need to make sure to download these artifacts also

Simple Exmaple:

JAXB Class

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "hello",
    "world"
})
@XmlRootElement(name = "root")
public class Root {

    @XmlElement(required = true)
    protected String hello;
    @XmlElement(required = true)
    protected String world;

    // Getters and Setters
}

XML

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <hello>JAXB</hello>
    <world>Jackson</world>
</root>

Test

public class TestJaxbJackson {
    public static void main(String[] args) throws Exception {
        JAXBContext context = JAXBContext.newInstance(Root.class);
        Unmarshaller unmarshaller = context.createUnmarshaller();
        InputStream is = TestJaxbJackson.class.getResourceAsStream("test.xml");
        Root root = (Root)unmarshaller.unmarshal(is);
        System.out.println(root.getHello() + " " + root.getWorld());

        ObjectMapper mapper = new ObjectMapper();
        JaxbAnnotationModule module = new JaxbAnnotationModule();
        mapper.registerModule(module);
        mapper.writeValue(System.out, root);
    }
}

Result

{"hello":"JAXB","world":"Jackson"}

Update

Also see this post. It looks like MOXy also offers this support.

Community
  • 1
  • 1
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • Works wonderful! Is it possible to alter the JSON representation by configuring Jackson only? Remember: I don't have write access to the Java classes with annotations. In my current setup (I only had to include the last four lines of your test) the [output](http://pastebin.com/raw.php?i=py5d07Ad) sadly includes object elements like 'scope', 'globalScope' and 'typeSubsituted'. I want to ommit those details and output only the data (name, attributes and element content). Is this possible and is this enough for incoming JSON to be transferred to JAXBElements again? – Sebastian Barth Sep 30 '14 at 16:05
  • Not sure about the extra elements. But for unmarshalling, look at the `ObjectMapper.readValue(...)` methods to unmarshal – Paul Samsotha Sep 30 '14 at 16:21
  • That doesn't seem to be a two-way transformation: [code](http://pastebin.com/raw.php?i=RwGpyW3W), [input](http://pastebin.com/raw.php?i=py5d07Ad), Exception: `Caused by: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "name" (class net.opengis.wps.v_1_0_0.GetCapabilities), not marked as ignorable (3 known properties: "language", "AcceptVersions", "service"])` – Sebastian Barth Sep 30 '14 at 16:27
  • It's because of those extra property that's not part of your jaxb classes. The unmarshalling works for the example above. I'm not really sure how you can get rid of those. – Paul Samsotha Sep 30 '14 at 16:43
  • 1
    Try creating the ObjectMapper with `new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);` – Paul Samsotha Sep 30 '14 at 16:46
  • That may work for the unmarshalling, but I'm still not sure how to stop them from being written in the first place – Paul Samsotha Sep 30 '14 at 16:46
  • It now unmarshalls with this option. Thanks for that! The unnecessary element problem still remains which bloats my JSON up to the doubled size. – Sebastian Barth Sep 30 '14 at 16:52
  • I found [this](http://stackoverflow.com/questions/24124149/how-to-json-marshal-jaxbelement-wrapped-responses-without-the-jaxbelement-wrappe) question. Their solution was to use [mix-in](http://wiki.fasterxml.com/JacksonMixInAnnotations) annotations, providing a partner class for each JAXBElement class. Sadly this is not a real option for me. Hopefully there is another one! – Sebastian Barth Sep 30 '14 at 17:08
  • The solution to the unnecessary elements problem was to serialize the real value of the `JAXBElement`. In fact I unluckily was serializing a `JAXBElement` instead of `JAXBElement`. I got the element via the method `getValue()` from the given type element. – Sebastian Barth Oct 01 '14 at 16:45
  • I was going to suggest that, for the main element, but I noticed you have other elements at the bottom of the json that were JAXBElements also, so I assumed you had a member like `List list` and I didn't think it would make a difference for those, just getting the value for the root element. Did it? – Paul Samsotha Oct 01 '14 at 16:48