Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to marshal an object via JAXB without any information about it?

Tags:

java

xml

jaxb

I have an object value, which is of some type, either @XmlRootElement-annotated, or not. I want to marshal it into XML:

String value1 = "test";
assertEquals("<foo>test</foo>", toXml("foo", value1));
// ...
@XmlRootElement
class Bar {
  public String bar = "test";
}
assertEquals("<foo><bar>test</bar></foo>", toXml("foo", new Bar()));

Can I do it with JAXB existing facilities, or I should create some custom analyzer?

like image 238
yegor256 Avatar asked Nov 10 '10 16:11

yegor256


2 Answers

You could leverage JAXBIntrospector to do the following:

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBIntrospector;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.namespace.QName;

public class Demo {


    public static void main(String[] args) throws Exception {
        Object value = "Hello World";
        //Object value = new Bar();

        JAXBContext jc = JAXBContext.newInstance(String.class, Bar.class);
        JAXBIntrospector introspector = jc.createJAXBIntrospector();
        Marshaller marshaller = jc.createMarshaller();
        if(null == introspector.getElementName(value)) {
            JAXBElement jaxbElement = new JAXBElement(new QName("ROOT"), Object.class, value);
            marshaller.marshal(jaxbElement, System.out);
        } else {
            marshaller.marshal(value, System.out);
        }
    }

    @XmlRootElement
    public static class Bar {

    }

}

With the above code when the JAXBElement is marshalled it will be qualified with an xsi:type attribute corresponding to the appropriate schema type:

<ROOT 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">Hello World</ROOT>

To eliminate the qualification you can simply change the line that creates the JAXBElement to:

JAXBElement jaxbElement = new JAXBElement(new QName("ROOT"), value.getClass(), value);

This will result in the following XML:

<ROOT>Hello World</ROOT>
like image 58
bdoughan Avatar answered Sep 19 '22 19:09

bdoughan


Here is how to marshal value1, which is a String. You can pass yourObject.getClass() to the JAXBElement constructor, and value1:

try {
    JAXBContext jc = JAXBContext.newInstance();
    Marshaller m = jc.createMarshaller();
    String value1 = "test";
    JAXBElement jx = new JAXBElement(new QName("foo"), value1.getClass(), value1);
    m.marshal(jx, System.out);
} catch (JAXBException ex) {
    ex.printStackTrace();
}

This works without using @XmlRootElement. The result of the code above was:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><foo>test</foo>

On the other part, this will not work with a Bar object: javax.xml.bind.JAXBException: myPackage.Bar is not known to this context. However, you can get the value from inside Bar, and create the JAXBElement with that, not the object itself.

like image 42
Daniel Szalay Avatar answered Sep 21 '22 19:09

Daniel Szalay