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 callinggetValue
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.
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
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
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
Printing Message on Console Without Using Main() Method
How to Get the Parent Base Class Object Super.Getclass()
JSON Parameter in Spring MVC Controller
Auto Resizing the Jtable Column Widths
Jaxb Mapping Cyclic References to Xml
Bouncy Castle:Pemreader => Pemparser
Accessing a File Inside a .Jar File
Netbeans - Error: Could Not Find or Load Main Class
Gwt: Timer and Scheduler Classes
Why Can't I Use \U000D and \U000A as Cr and Lf in Java
Java Native Method Source Code
Where Are Generic Types Stored in Java Class Files