19

Is it possible to convert a javax.xml.bind.annotation.XmlType to the String representation of the XML?

Example:

The following class Req is from a third party library so I can't override the toString() method.

@javax.xml.bind.annotation.XmlAccessorType(javax.xml.bind.annotation.XmlAccessType.FIELD)
@javax.xml.bind.annotation.XmlType(name = "req", propOrder = {"myDetails", "customerDetails"})
public class Req  {
...
}

In my application I want to simply get a String representation of the XML so that I can log it to a file:

<Req>
    <MyDetails>
    ...
    </MyDetails>
    <CustomerDetails>
    ...
    </CustomerDetails>
</Req>

When I try to use JAXB and Marshall to convert to XML String:

JAXBContext context = JAXBContext.newInstance(Req.class);
Marshaller marshaller = context.createMarshaller();
StringWriter sw = new StringWriter();
marshaller.marshal(instanceOfReq, sw);
String xmlString = sw.toString();

I get the following exception:

javax.xml.bind.MarshalException
    - with linked exception:
    [com.sun.istack.SAXException2: unable to marshal type "mypackage.Req" as an element because it is missing an @XmlRootElement annotation]

I have had a look at the other classes within the third party library and none of them use the @XmlRootElement annotation. Any way around this?

ryan
  • 5,039
  • 13
  • 35
  • 42

2 Answers2

27

You can use JAXB and marshall it to xml string

JAXBContext context = JAXBContext.newInstance(Req.class);
Marshaller marshaller = context.createMarshaller();
StringWriter sw = new StringWriter();
marshaller.marshal(instanceOfReq, sw);

String xmlString = sw.toString();
Bala R
  • 107,317
  • 23
  • 199
  • 210
  • 4
    A word of warning to the OP: `JAXBContext`s are expensive (slow) to create. Create and reuse a single instance. – Matt Ball May 17 '11 at 14:14
  • 1
    Tried using JAXB and Marshall but get the MarshalException described in the above post. – ryan May 17 '11 at 14:53
  • and you cannot change the class Req to add XmlRoot annotation? – Bala R May 17 '11 at 14:54
  • No unfortunately not - it's contained within a third party library. – ryan May 17 '11 at 14:57
  • 8
    ok, try this `marshaller.marshal(new JAXBElement( new QName("","Req"),Req.class,instanceOfReq), sw);` – Bala R May 17 '11 at 15:07
  • I'm not very sure about it and I got the idea from this post http://jaxb.java.net/guide/Different_ways_of_marshalling.html – Bala R May 17 '11 at 15:07
  • @Bala R - Wrapping instanceOfReq in an instance of JAXBElement is the right way to handle this use case. – bdoughan May 17 '11 at 15:33
  • And on a side note, is there an easy way to stop the XML file header from being included in the output? E.g. "". If not, I could always do a substring to remove it. – ryan May 18 '11 at 08:16
  • Look at http://jaxb.java.net/guide/Different_ways_of_marshalling.html under "marshalling into a subtree". I'm not sure but I think that's what you want. – Tyler May 24 '11 at 20:11
7

Addding to what Bala R indicated, you can do this if your JAXB element don't have the @xmlrootelement

JAXBContext context = JAXBContext.newInstance(YourClass.class);
            Marshaller marshaller = context.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
            StringWriter sw = new StringWriter();
            JAXBElement jx = new JAXBElement(new QName("YourRootElement"), YourClass.class, input);
            marshaller.marshal(jx, sw);
            String xmlString = sw.toString();

This was also stated here.

Community
  • 1
  • 1
Christian Vielma
  • 15,263
  • 12
  • 53
  • 60