How to Programmatically Configure Jaxb

Is it possible to programmatically configure JAXB?

You could create a generic Wrapper object like the following:

Wrapper

You could create a generic wrapper class with a List property annotated with @XmlAnyElement(lax=true). The type of the object used to populate this list will be based on its root element (see: http://blog.bdoughan.com/2010/08/using-xmlanyelement-to-build-generic.html).

package forum13272288;

import java.util.*;
import javax.xml.bind.annotation.XmlAnyElement;

public class Wrapper<T> {

private List<T> items = new ArrayList<T>();

@XmlAnyElement(lax=true)
public List<T> getItems() {
return items;
}

}

Address

You will need to annotate the possible contents of the list with @XmlRootElement.

package forum13272288;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Address {

}

Person

package forum13272288;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Person {

}

Demo

The demo code below demonstrates how to use the Wrapper class. Since the root element can be different you will need to specify that you want to unmarshal to the wrapper class. Alternatively you could leverage the @XmlElementDecl annotation to associate multiple root elements with the wrapper class (see: http://blog.bdoughan.com/2012/07/jaxb-and-root-elements.html).

package forum13272288;

import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;

public class Demo {

public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Wrapper.class, Person.class, Address.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

StreamSource personsXML = new StreamSource("src/forum13272288/persons.xml");
JAXBElement<Wrapper> wrapper1 = unmarshaller.unmarshal(personsXML, Wrapper.class);
marshaller.marshal(wrapper1, System.out);

StreamSource addressesXML = new StreamSource("src/forum13272288/addresses.xml");
JAXBElement<Wrapper> wrapper2 = unmarshaller.unmarshal(addressesXML, Wrapper.class);
marshaller.marshal(wrapper2, System.out);
}

}

Output

Below is the output from running the demo code. The files persons.xml and addresses.xml look just like there corresponding output.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persons>
<person/>
<person/>
</persons>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addresses>
<address/>
<address/>
</addresses>

For More Information

  • http://blog.bdoughan.com/2012/11/creating-generic-list-wrapper-in-jaxb.html

Programmatically add or set JAXB XmlRootElement

You just need to use one of the unmarshal methods that take a Class parameter.

StreamSource source = new StreamSource(new StringReqder(xml));
return (T) u.unmarshal(source, clazz).getValue();

Note

  • The result of the unmarshal method will be an instance of JAXBElement this holds the root element information you can get the unmarshalled object by calling getValue on it.
  • For marshalling you can supply the root information by wrapping your object in an instance of JAXBElement and then marshal that.

How do I programmatically create XML from Java?

The B in JAXB stands for Bean so no, there's no way to use JAXB without defining beans.

You just want to dinamically create an XML so take a look at jOOX for example (link to full Gist)

Document document = JOOX.builder().newDocument();
Element root = document.createElement("contacts");
document.appendChild(root);

for (String name : new String[]{"John", "Jessica", "Peter"}) {
$(root).append(
$("contact"
, $("name", name)
, $("active", "true")
)
);
}

How do I marshal java.util.List with JAXB like JAX-RS (CXF, and Jersey) do

Blaise Doughan I believe shows a good solution for this problem here: Is it possible to programmatically configure JAXB?

and

http://blog.bdoughan.com/2012/11/creating-generic-list-wrapper-in-jaxb.html

and somewhat here albeit slightly different use case:

http://blog.bdoughan.com/2012/02/xmlanyelement-and-xmladapter.html

Universal adapter for JAXB

You can use an XmlAdapter like this:

import java.io.*;
import javax.xml.bind.*;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.*;

@XmlType
class Valued {
@XmlAttribute(name="value")
public String value;
}

class ValuedAdapter extends XmlAdapter<Valued, String> {
public Valued marshal(String s) {
Valued v = new Valued();
v.value = s;
return v;
}
public String unmarshal(Valued v) {
return v.value;
}
}

@XmlRootElement
class Person {

@XmlJavaTypeAdapter(ValuedAdapter.class)
@XmlElement
String firstName;

@XmlJavaTypeAdapter(ValuedAdapter.class)
@XmlElement
String lastName;

}

class SO12928971 {
public static void main(String[] args) throws Exception {
Person p = new Person();
p.firstName = "John";
p.lastName = "Doe";
JAXBContext jc = JAXBContext.newInstance(Person.class);
StringWriter sw = new StringWriter();
jc.createMarshaller().marshal(p, sw);
String xml = sw.toString();
System.out.println(xml);
StringReader sr = new StringReader(xml);
p = (Person)jc.createUnmarshaller().unmarshal(sr);
assert "John".equals(p.firstName);
assert "Doe".equals(p.lastName);
}
}

The idea here is that XML Schema and therefore also JAXB has a clear distinction between element names and content types, even though many documents have a clear one-to-one correspondence between these two. So in the above code, the type Valued describes something that has a value attribute, without regards for the element name. The members you want to serialize are annotated as @XmlElement with no name included in that annotation. So they will generate elements with a name derived from the name of the member. The @XmlJavaTypeAdapter annotation will cause the serializer to treat these members as if their types vere Valued. So that is what their XML content type will be.

The schema for the above code looks like this:

<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">

<xs:element name="person" type="person"/>

<xs:complexType name="person">
<xs:sequence>
<xs:element name="firstName" type="valued" minOccurs="0"/>
<xs:element name="lastName" type="valued" minOccurs="0"/>
</xs:sequence>
</xs:complexType>

<xs:complexType name="valued">
<xs:sequence/>
<xs:attribute name="value" type="xs:string"/>
</xs:complexType>
</xs:schema>

Set MOXy as JAXB Provider without properties file in the same package

There are several ways how to set MOXy as JAXB Provider.

  1. To set system property JAXBContext.JAXB_CONTEXT_FACTORY to org.eclipse.persistence.jaxb.JAXBContextFactory

    • http://docs.oracle.com/javaee/7/api/javax/xml/bind/JAXBContext.html#JAXB_CONTEXT_FACTORY
  2. To create META-INF/services/javax.xml.bind.JAXBContext file with org.eclipse.persistence.jaxb.JAXBContextFactory

    • http://docs.oracle.com/cd/E24329_01/web.1211/e24964/data_types.htm#WSGET346
  3. using org.eclipse.persistence.jaxb.JAXBContextFactory

    • Can I replace jaxb.properties with code?

How would I marshal a List of Jaxb Elements without making a wrapper class?

If you don't want to create a wrapper class you could convert the collection into an array, place that array in a JAXBElement and then marshal it.

For example:

public class JAXBArrayWriter {

public static class Item {
@XmlValue
protected String value;

public Item() {}

public Item(String value) {
this.value = value;
}
}

public static void main (String [] args) throws Exception {
List<Item> items = new ArrayList<Item>();
items.add(new Item("one"));
items.add(new Item("two"));
JAXBContext jc = JAXBContext.newInstance(Item[].class);
JAXBElement<Item[]> root = new JAXBElement<Item[]>(new QName("items"),
Item[].class, items.toArray(new Item[items.size()]));
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
StringWriter writer = new StringWriter();
marshaller.marshal(root, writer);
System.out.println(writer.toString());
}
}

which produces the following document:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<items>
<item>one</item>
<item>two</item>
</items>


Related Topics



Leave a reply



Submit