Is there way one can convert JAXB class (not its object) to xml template.
For example
Below code is taken from http://www.javacodegeeks.com/2011/02/jaxb-generate-xml-xsd.html
public static void main(String[] args) throws JAXBException
{
ObjectFactory factory = new ObjectFactory();
UserT user = factory.createUserT();
user.setUserName("Sanaulla");
ItemT item = factory.createItemT();
item.setItemName("Seagate External HDD");
item.setPurchasedOn("August 24, 2010");
item.setAmount(new BigDecimal("6776.5"));
ItemListT itemList = factory.createItemListT();
itemList.getItem().add(item);
ExpenseT expense = factory.createExpenseT();
expense.setUser(user);
expense.setItems(itemList);
JAXBContext context = JAXBContext.newInstance("generated");
JAXBElement element = factory.createExpenseReport(expense);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty("jaxb.formatted.output",Boolean.TRUE);
marshaller.marshal(element,System.out);
}
In above code object of class Element has been create to marshall. My question is what if I don't have object of JAXB class, will I still be able to generate xml template (with no values)
Related
Given something like:
<root>
<wrapper>
<wrapped id="..."/>
<wrapped id="..."/>
</wrapper>
</root>
how can I map it to this POJO:
public class Root {
public Set<UUID> myIds = new LinkedHashSet();
}
I am wondering since #XmlElement( name = "wrapped" ) #XmlElementWrapper( name = "wrapper" ) works somewhat similar to what I want, is there something to get the attribute?
note: i am not using moxy so as far as I know, I cannot use xpaths. I am trying to avoid the #XmlJavaTypeAdapter route.
You need to modify your root class a little bit,
so that it will contain a Set<Wrapped> instead of a Set<UUID>.
#XmlRootElement(name = "root")
public class Root {
#XmlElementWrapper(name = "wrapper")
#XmlElement(name = "wrapped")
public Set<Wrapped> myWrappeds = new LinkedHashSet<>();
}
And you need a separate class for the <wrapped> elements.
Surprisingly for me, you don't need an #XmlJavaAdapter for id here, because JAXB already has a built-in converter between java.util.UUID and String.
public class Wrapped {
#XmlAttribute(name = "id")
public UUID id;
}
I have checked the above with this XML input file
<root>
<wrapper>
<wrapped id="550e8400-e29b-11d4-a716-446655440000"/>
<wrapped id="550e8400-e29b-11d4-a716-446655440001"/>
</wrapper>
</root>
and this main method which reproduces the original XML:
public static void main(String[] args) throws Exception {
JAXBContext context = JAXBContext.newInstance(Root.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
File file = new File("root.xml");
Root root = (Root) unmarshaller.unmarshal(file);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
I have a org.w3c.dom.Element that I'm returning from my XmlAdapter for a custom #XmlElement and I'd like to include it as part of a JAXB object as arbitrary XML (I'm aware I'll have to hand-craft the XSD). However, JAXB complains with
org.w3c.dom.Element is an interface, and JAXB can't handle interfaces.
Apparently the w3c XML types are not supported as Java types, which is a shame. But further than this, I get the same error when I use javax.xml.transform.Result which is apparently supported.
How can I include arbitrary XML elements as elements in JAXB?
Note: as per https://forums.oracle.com/thread/1668210 I've also tried
MessageFactory factory = MessageFactory.newInstance();
message = factory.createMessage();
SOAPElement element = message.getSOAPBody().addDocument(doc);
but that is also giving the same error.
TL;DR
You can have an XmlAdapter that converts you domain object to an instance of org.w3c.dom.Element as long as you specify the value type as Object (not Element).
Below is a full example.
XmlAdapter
A field/property of type java.lang.Object will keep unknown content as DOM nodes. You can leverage this in your use case by specifying the value type in your XmlAdapter as Object. You will need to ensure that the root element returned from the marshal method matches the field/property as defined by the #XmlElement annotation.
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.parsers.*;
import org.w3c.dom.*;
public class BarAdapter extends XmlAdapter<Object, Bar>{
private DocumentBuilder documentBuilder;
public BarAdapter() {
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
documentBuilder = dbf.newDocumentBuilder();
} catch(Exception e) {
// TODO - Handle Exception
}
}
#Override
public Bar unmarshal(Object v) throws Exception {
Bar bar = new Bar();
Element element = (Element) v;
bar.value = element.getTextContent();
return bar;
}
#Override
public Object marshal(Bar v) throws Exception {
Document document = documentBuilder.newDocument();
Element root = document.createElement("bar");
root.setTextContent(v.value);
return root;
}
}
Java Model
Foo
The #XmlJavaTypeAdapter annotation is used to reference the XmlAdapter.
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Foo {
#XmlJavaTypeAdapter(BarAdapter.class)
private Bar bar;
}
Bar
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
public class Bar {
String value;
}
Demo Code
Demo
Since there is a cost to creating the DocumentBuilderFactory we can leverage JAXB's ability to handle stateful instances of XmlAdapter by setting an instance on the Marshaller.
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Foo.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum18272059/input.xml");
Foo foo = (Foo) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setAdapter(new BarAdapter());
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(foo, System.out);
}
}
input.xml/Output
<?xml version="1.0" encoding="UTF-8"?>
<foo>
<bar>Hello World</bar>
</foo>
I have a string of that is an XML string and it could correspond to one of several objects that are jaxb generated schema files.
I don't know what object it is ahead of time.
How do convert this XML string to an jaxb xml object? Some type of unmarshalling?
How do I determine which object it is assigned to?
How do I instantiate the object once it is converted from xml string to the object?
You could do something like the following:
Foo
As long as there is a root element associated with your class via an #XmlRootElement or #XmlElementDecl annotation you don't need to specify the type of class that you are unmarshalling (see: http://blog.bdoughan.com/2012/07/jaxb-and-root-elements.html).
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Foo {
private String bar;
public String getBar() {
return bar;
}
public void setBar(String bar) {
this.bar = bar;
}
}
Demo
To unmarshal from a String simply wrap the String in an instance of StringReader. The unmarshal operation will convert the XML into an instance of your domain class. If you don't know what class you will have to use instanceof or getClass() to determine what type it is.
import java.io.StringReader;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Foo.class);
String xml = "<foo><bar>Hello World</bar></foo>";
StringReader reader = new StringReader(xml);
Unmarshaller unmarshaller = jc.createUnmarshaller();
Object result = unmarshaller.unmarshal(reader);
if(result instanceof Foo) {
Foo foo = (Foo) result;
System.out.println(foo.getBar());
}
}
}
Output
Hello World
Unmarshaller yourunmarshaller = JAXBContext.NewInstance(yourClass).createUnMarshaller();
JAXBElement<YourType> jaxb = (yourunmarshaller).unmarshal(XMLUtils.getStringSource([your object]), [the class of your object].class);
If you have schema files for the XML objects, which you would if you're using JAXB, run a validate on the XML.
Java XML validation against XSD Schema
If you generate objects from XSD, then JAXB generated an ObjectFactory class in the same package as all the type classes.
JAXBContext jaxbContext = JAXBContext.newInstance("your.package.name");
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Here "your.package.name" stands for the package name of your ObjectFactory class.
The unmarshaller can now convert your XML into objects:
public Object createObjectFromString(String messageBody) throws JAXBException {
return unmarshaller.unmarshal(new StringReader(messageBody));
}
If this is successful, a JAXBElement object will be returned:
try {
JAXBElement jaxbElement= (JAXBElement) createObjectFromString(messageBody);
} catch (JAXBException e) {
// unmarshalling was not successful, take care of the return object
}
If you have a jaxbElement object returned, you can call getValue() for the wrapped object, of getDeclaredType() for it's class.
With this method, you don't need to know the type of the target object in advance.
I am writing a code to set XmlTransient at runtime using MOXy. Here is the part of the code which is adapted from the example on http://blog.bdoughan.com/2011/06/moxy-extensible-models-refresh-example.html
public void setXmlTransient(Class<?> domainClass, String propertyName) {
XmlTransient xmlTransient = new XmlTransient();
xmlTransient.setJavaAttribute(propertyName);
JavaType javaType = getJavaType(domainClass);
javaType.getJavaAttributes().getJavaAttribute().add(objectFactory.createXmlTransient(xmlTransient));
}
Since I am doing this programmatically, I need to be able to create the propertyName exactly the same way as MOXy does. For most getter method names, like getOrder, the property name is done by removing get from the method name and change upper-case O to lower-case o, i.e. property name is order. However, I am hitting the case which my getter method is getXInA but xInA doesn't seem to be a valid property name. MOXy throws a warning like
Ignoring attribute [xInA] on class [Atom] as no Property was generated for it.
Does anyone know what the rules are used by MOXy for creating the property name from getters? or know where I can find out about this without reading the MOXy source code?
SHORT ANSWER
Because there are two capital letters in a row the property name is going to be XInA.
LONG ANSWER
Domain Model (Foo)
Below is a sample Java class with the property from your question.
package forum14945664;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Foo {
private String x;
public String getXInA() {
return x;
}
public void setXInA(String x) {
this.x = x;
}
}
MetadataSource (ExampleMetadataSource)
MetadataSource is a programmatic way to provide MOXy with the mapping metadata.
package forum14945664;
import java.util.*;
import org.eclipse.persistence.jaxb.metadata.MetadataSourceAdapter;
import org.eclipse.persistence.jaxb.xmlmodel.*;
import org.eclipse.persistence.jaxb.xmlmodel.JavaType.*;
import org.eclipse.persistence.jaxb.xmlmodel.XmlBindings.*;
public class ExampleMetadataSource extends MetadataSourceAdapter {
private ObjectFactory objectFactory;
private Map<Class<?>, JavaType> javaTypes;
private XmlBindings xmlBindings;
public ExampleMetadataSource() {
objectFactory = new ObjectFactory();
javaTypes = new HashMap<Class<?>, JavaType>();
xmlBindings = new XmlBindings();
xmlBindings.setPackageName("forum14945664");
xmlBindings.setJavaTypes(new JavaTypes());
}
#Override
public XmlBindings getXmlBindings(Map<String, ?> properties, ClassLoader classLoader) {
return xmlBindings;
}
public JavaType getJavaType(Class<?> clazz) {
JavaType javaType = javaTypes.get(clazz);
if(null == javaType) {
javaType = new JavaType();
javaType.setName(clazz.getSimpleName());
javaType.setJavaAttributes(new JavaAttributes());
xmlBindings.getJavaTypes().getJavaType().add(javaType);
javaTypes.put(clazz, javaType);
}
return javaType;
}
public void setXmlTransient(Class<?> domainClass, String propertyName) {
XmlTransient xmlTransient = new XmlTransient();
xmlTransient.setJavaAttribute(propertyName);
JavaType javaType = getJavaType(domainClass);
javaType.getJavaAttributes().getJavaAttribute().add(objectFactory.createXmlTransient(xmlTransient));
}
}
Specify MOXy as JAXB Provider (jaxb.properties)
To specify MOXy as the JAXB provider you need to include a file called jaxb.properties in the same package as your domain model with the following entry.
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Demo
In the demo code below we will create a JAXBContext based on the domain model and we will marshal an instance to XML. Then we will use the MetadataSource to make the property transient, refresh the JAXBContext and marshal the instance again.
package forum14945664;
import java.util.*;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.JAXBContextProperties;
import org.eclipse.persistence.jaxb.JAXBHelper;
public class Demo {
public static void main(String[] args) throws Exception {
ExampleMetadataSource metadata = new ExampleMetadataSource();
Map<String, Object> properties = new HashMap<String, Object>(1);
properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, metadata);
JAXBContext jc = JAXBContext.newInstance(new Class[] {Foo.class}, properties);
Foo foo = new Foo();
foo.setXInA("Hello World");
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(foo, System.out);
metadata.setXmlTransient(Foo.class, "XInA");
JAXBHelper.getJAXBContext(jc).refreshMetadata();
marshaller.marshal(foo, System.out);
}
}
Output
First we see the XInA property marshalled, then after we make it transient we see that it is not in the XML from the second marshal operation.
<?xml version="1.0" encoding="UTF-8"?>
<foo>
<XInA>Hello World</XInA>
</foo>
<?xml version="1.0" encoding="UTF-8"?>
<foo/>
The question is a bit theoretical, what is the cost of creating JAXB context, marshaller and unmarshaller?
I've found that my code could benefit from keeping the same JAXB context and possibly the same marshaller for all marshaling operations rather than creating context and marshaller on each marshaling.
So what is the cost of creating JAXB context and marshaller/unmarshaller? Is it okay to create context+marshaller for each marshaling operation or it's better to avoid it?
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.
JAXBContext is thread safe and should only be created once and reused to avoid the cost of initializing the metadata multiple times. Marshaller and Unmarshaller are not thread safe, but are lightweight to create and could be created per operation.
Ideally, you should have a singleton JAXBContext and local instances of Marshaller and Unmarshaller.
JAXBContext instances are thread-safe while Marshaller and Unmarshaller instances are not thread-safe and should never be shared across threads.
It's a pity that this isn't specifically described in the javadoc. What I can tell is that Spring uses a global JAXBContext, shared between threads, whereas it creates a new marshaller for each marshalling operation, with a javadoc comment in the code saying that JAXB marshallers are not necessarily thread-safe.
The same is said on this page:https://javaee.github.io/jaxb-v2/doc/user-guide/ch03.html#other-miscellaneous-topics-performance-and-thread-safety.
I would guess that creating a JAXBContext is a costly operation, because it involves scanning classes and packages for annotations. But measuring it is the best way to know.
JAXB 2.2 (JSR-222) has this to say, in section "4.2 JAXBContext":
To avoid the overhead involved in creating a JAXBContext instance, a
JAXB application is encouraged to reuse a JAXBContext instance. An
implementation of abstract class JAXBContext is required to be
thread-safe, thus, multiple threads in an application can share the
same JAXBContext instance.
[..]
JAXBContext class is designed to be immutable and thus threadsafe.
Given the amount of dynamic processing that potentially could take
place when creating a new instance of JAXBContxt, it is recommended
that a JAXBContext instance be shared across threads and reused as
much as possible to improve application performance.
Unfortunately, the specification does not make any claims regarding thread-safety of Unmarshaller and Marshaller. So it is best to assume they are not.
I solved this problem using:
shared thread safe JAXBContext and thread local un/marschallers
(so theoretically, there will be as many un/marshaller instances as there are threads which accessed them)
with synchronization only on un/marshaller's initialization.
public class MyClassConstructor {
private final ThreadLocal<Unmarshaller> unmarshallerThreadLocal = new ThreadLocal<Unmarshaller>() {
protected synchronized Unmarshaller initialValue() {
try {
return jaxbContext.createUnmarshaller();
} catch (JAXBException e) {
throw new IllegalStateException("Unable to create unmarshaller");
}
}
};
private final ThreadLocal<Marshaller> marshallerThreadLocal = new ThreadLocal<Marshaller>() {
protected synchronized Marshaller initialValue() {
try {
return jaxbContext.createMarshaller();
} catch (JAXBException e) {
throw new IllegalStateException("Unable to create marshaller");
}
}
};
private final JAXBContext jaxbContext;
private MyClassConstructor(){
try {
jaxbContext = JAXBContext.newInstance(Entity.class);
} catch (JAXBException e) {
throw new IllegalStateException("Unable to initialize");
}
}
}
Even better!! Based on the good solution from the post above, create the context just-once in the constructor, and save it instead of the class.
Replace the line:
private Class clazz;
with this one:
private JAXBContext jc;
And the main constructor with this one:
private Jaxb(Class clazz)
{
this.jc = JAXBContext.newInstance(clazz);
}
so in the getMarshaller/getUnmarshaller you can remove this line:
JAXBContext jc = JAXBContext.newInstance(clazz);
This improvement makes, in my case, that processing times drops from 60~70ms to just 5~10ms
I usually solve problems like this with a ThreadLocal class pattern.
Given the fact that you need a different marshaller for each Class, you can combine it with a singleton-map pattern.
To save you 15 minutes, of work. Here follows my implementation of a thread-safe Factory for Jaxb Marshallers and Unmarshallers.
It allows you to access the instances as follows ...
Marshaller m = Jaxb.get(SomeClass.class).getMarshaller();
Unmarshaller um = Jaxb.get(SomeClass.class).getUnmarshaller();
And the code you will need is a little Jaxb class that looks as follows:
public class Jaxb
{
// singleton pattern: one instance per class.
private static Map<Class,Jaxb> singletonMap = new HashMap<>();
private Class clazz;
// thread-local pattern: one marshaller/unmarshaller instance per thread
private ThreadLocal<Marshaller> marshallerThreadLocal = new ThreadLocal<>();
private ThreadLocal<Unmarshaller> unmarshallerThreadLocal = new ThreadLocal<>();
// The static singleton getter needs to be thread-safe too,
// so this method is marked as synchronized.
public static synchronized Jaxb get(Class clazz)
{
Jaxb jaxb = singletonMap.get(clazz);
if (jaxb == null)
{
jaxb = new Jaxb(clazz);
singletonMap.put(clazz, jaxb);
}
return jaxb;
}
// the constructor needs to be private,
// because all instances need to be created with the get method.
private Jaxb(Class clazz)
{
this.clazz = clazz;
}
/**
* Gets/Creates a marshaller (thread-safe)
* #throws JAXBException
*/
public Marshaller getMarshaller() throws JAXBException
{
Marshaller m = marshallerThreadLocal.get();
if (m == null)
{
JAXBContext jc = JAXBContext.newInstance(clazz);
m = jc.createMarshaller();
marshallerThreadLocal.set(m);
}
return m;
}
/**
* Gets/Creates an unmarshaller (thread-safe)
* #throws JAXBException
*/
public Unmarshaller getUnmarshaller() throws JAXBException
{
Unmarshaller um = unmarshallerThreadLocal.get();
if (um == null)
{
JAXBContext jc = JAXBContext.newInstance(clazz);
um = jc.createUnmarshaller();
unmarshallerThreadLocal.set(um);
}
return um;
}
}
Creating JAXBContext within a enum and accessing it within application Thread to create Marshaller/Unmarshaller will suffice.
public enum MyApplicationJAXBContext {
REQ(Request.class), RESP(Response.class);
private final JAXBContext jaxbContext;
MyApplicationJAXBContext(Class contextClass) {
try {
jaxbContext = JAXBContext.newInstance(contextClass);
} catch (JAXBException e)
throw new RunTimeException(e);
// Lets caller decide what to do ?
}
}
public JAXBContext getJaxbContext() {
return jaxbContext;
}
}
public class MyAppCallable implements Callable<Response> {
private final Request req;
public MyAppCallable(Request req) {
this.req = req;
}
public Response call() {
Marshaller marshaller = MyApplicationJAXBContext.REQ.getJaxbContext().createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
// Anything else you want to configure properties
Unmarshaller unmarshaller = MyApplicationJAXBContext.RESP.getJaxbContext().createUnmarshaller();
/**
All other logic you want to do after req/rsp usage and return Response
**/
}
}