We have a class, with no control over the source, so no way to annotate it for JAXB. We also have a framework to take care of marshaling. Is there any way for this framework to ask that class whether it is marshallable when no annotations are present?
There is no standard mechanism, but I have seem people accomplish this by trying to create the JAXBContext on the class:
public boolean isValidJAXBClass(Class aClass) {
try {
JAXBContext.newInstance(aClass);
} catch(JAXBException e) {
return false;
}
return true;
}
You don't need any annotations to marshal a JAXB object. You can get around having to
have an #XmlRootElement by wrapping it in a JAXBElement.
If you want an alternative means to represent the metadata, EclipseLink JAXB (MOXy) has a externalized binding file based on the JAXB metadata
A sample file looks something like:
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm">
<java-types>
<java-type name="org.example.order.PurchaseOrder">
<java-attributes>
<xml-attribute java-attribute="id"/>
<xml-element java-attribute="customer">
<xml-java-type-adapter value="org.example.order.CustomerAdapter"/>
</xml-element>
<xml-element java-attribute="lineItems" name="line-item"/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
For more information see:
http://wiki.eclipse.org/EclipseLink/Examples/MOXy/EclipseLink-OXM.XML
Related
I have autogenerated java classes from xsd using xsd2java. I cannot modify neither xsd nor the java classes.
Problem: in one class an element of List<JAXBElement> is generated.
If I now add any JAXBElement, the jackson xml marshaller won't show the proper xml element, but the properties of the JAXBElement serialized. Like declaredType, scope, etc. See below.
#XmlRootElement(name = "bookingRequest")
public class AutogeneratedReq {
private List<JAXBElement<?>> someElements;
}
Usage:
AutogeneratedReq req = new AutogeneratedReq();
JAXBElement<?> person = new ObjectFactory().createPerson();
req.getSomeElements().add(person);
Result:
<someElements>
<JAXBElement>
<name>person</name>
<declaredType>net.some.company.Person</declaredType>
<scope>net.some.company</scope><value someattribues="test"/>
<nil>false</nil>
<globalScope>false</globalScope>
<typeSubstituted>false</typeSubstituted>
</JAXBElement>
</someElements>
Question: how can I tell jackson or spring-mvc to generate proper xml, and not JAXBElement serialization explicit?
I don't know which xsd2java utility you currently use, but you can try the following maven plugin to generate Java classes from XSD files.
https://github.com/highsource/jaxb2-basics/wiki/Using-JAXB2-Basics-Plugins
And then you can use following extension to create correctly typed POJO's.
https://github.com/highsource/jaxb2-basics/wiki/JAXB2-Simplify-Plugin
BUT even if you can create typed POJO attributes, the XML file generated from this POJO may not be 100% valid against original XSD file.
<jaxb:bindings multiple="true" node="//xs:element[#name='someElement']//xs:complexType//xs:choice//xs:element">
<simplify:as-element-property/>
</jaxb:bindings>
I have a couple of java classes that I want to convert to xml using jaxb. (I have no need to generate the classes based on the schema) I need to be able to map the class to different xml formats so I do not want to use annotations. From what I've seen my best option seems to be to use external xml bindings. So I wanted to know:
1) I am using eclipse. I am new to JAXB and I would like to know how to integrate external bindings using eclipse?
2) What other options other than external xml bindings are available?
I think you best option is to use MOXy XML bindings:
http://www.eclipse.org/eclipselink/documentation/2.6/moxy/runtime003.htm
This allows you to define XML<->Java mappings in form of XML files instead of annotations:
<?xml version="1.0" encoding="US-ASCII"?>
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="example">
<java-types>
<java-type name="Customer">
<xml-root-element name="customer-info" />
<java-attributes>
<xml-attribute java-attribute="custId" name="customer-id" />
<xml-element java-attribute="picture" name="picture-hex">
<xml-schema-type name="hexBinary" />
<xml-java-type-adapter
value="example.adapters.MyHexConverter" />
</xml-element>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
You can use this file via JAXBContextProperties.OXM_METADATA_SOURCE property:
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, iStream);
JAXBContext ctx = JAXBContext.newInstance(new Class[] { Customer.class }, properties);
So if you want several different mappings for the same class, just write several XML bindings and create your JAXBContext with corresponding files. I think this is the best options right now, with MOXy
With pure JAXB RI you can write an own annotations reader. I did this once with Annox:
http://confluence.highsource.org/display/ANX/JAXB+User+Guide
Another option was JBoss JAXBIntroductions, also based on a custom annotations reader:
https://developer.jboss.org/wiki/JAXBIntroductions
But I'm not sure this is live anymore.
Since you want multiple mappings, you'll have to write them (all but one) manually. You can generate one set of mappings as annotations, but further mappings will have to be written manually. Or, let's say, I'm not aware of a plugin or tool which would generate, for instance, MOXy XML bindings. Wouldn't be a big problem to write one though.
You may also take a completely different approach. Instead of mapping one central model with different mappings/format, you can have map a separate package of DTOs onto these formats. And then convert between your DTOs and the central model. Something like
XML(1) <-> DTO(1)|<-\
XML(2) <-> DTO(2)|<--*->Model
XML(3) <-> DTO(3)|<-/
Thus you'll have clean DTOs per exchange format (which you can generate out of schemas) and a single central business model (to rule them all). You'll have to convert between DTOs and the Model, this can be handled with a tool like Dozer.
If this is a better approach or not depends on how complex your formats are and how different they are fron one another.
Concerning your questions:
1) There's nothing special about Eclipse, just add MOXy as dependency and follow the docs.
2) I've described a few options above.
See "Passing Customization Files to the JAXB Binding Compiler" here:
https://docs.oracle.com/javase/tutorial/jaxb/intro/custom.html
You could write a script to integrate into Eclipse. Or you could use a Maven or Ant task.
Your only options are annotations or XML bindings.
I want to persist an object tree to XML using EclipseLink MOXy. But I want all fields of type double to be written using a custom DoubleAdapter. I know that I can do that with package based annotation like
#XmlJavaTypeAdapters({ #XmlJavaTypeAdapter(type = double.class, value = DoubleAdapter.class) })
package example;
The problem is, that I have to add this to every package, which seems very stupid.
I even tried it using an bindings.xml file, but again it is limited to one package.
Is there a way to configure the JAXBContext such that it always uses the DoubleAdapter when it encounters an object of type double?
Update
I tried using the following bindings.xml
<?xml version="1.0"?>
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm" package-name="java.lang">
<java-types>
<java-type name="Double">
<xml-java-type-adapter value="moxy.DoubleAdapter" />
<java-attributes />
</java-type>
</java-types>
</xml-bindings>
But then the creation of the JaxbContext results in a NullPointerException. Why?
Map<String, Object> props = new HashMap<>();
props.put(JAXBContextProperties.OXM_METADATA_SOURCE, "bindings.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(new Class[] { Foo.class }, props);
Adding a global XmlAdapter at class level via XML metadata this way works for my own classes, but it somehow does not work for Double?
Ok, I debugged through the process and found that java.lang.Double is listed in the XMLToJavaTypeMap. This leads to typeInfoMap not containing a TypeInfo, which leads to the NPE in org.eclipse.persistence.jaxb.compiler.XMLProcessor.processXML(). So, type infos are not generated for Java built in types. Why?
Btw, if I want the adapter to be used for double and Double, I have to set
#XmlJavaTypeAdapters({
#XmlJavaTypeAdapter(type = double.class, value = DoubleAdapter.class),
#XmlJavaTypeAdapter(type = Double.class, value = DoubleAdapter.class)
})
package example;
But how do I refer to a primitive type like double in the XML bindings file?
Update 2
Specifying bindings on package level as XML like (note the primitive double)
<?xml version="1.0"?>
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm" package-name="foo">
<xml-java-type-adapters>
<xml-java-type-adapter value="foo.DoubleAdapter" type="double"/>
<xml-java-type-adapter value="foo.DoubleAdapter" type="java.lang.Double"/>
</xml-java-type-adapters>
</xml-bindings>
results in
Exception in thread "main" javax.xml.bind.JAXBException: Provider org.eclipse.persistence.jaxb.JAXBContextFactory could not be instantiated: javax.xml.bind.JAXB
Exception:
Exception Description: An invalid XmlJavaTypeAdapter [foo.DoubleAdapter] was specified for package [foo]. Possible causes are an incorrect adapter class name or
the wrong loader has been set.
- with linked exception:
[Exception [EclipseLink-50065] (Eclipse Persistence Services - 2.5.1.v20130918-f2b9fc5): org.eclipse.persistence.exceptions.JAXBException
Exception Description: An invalid XmlJavaTypeAdapter [foo.DoubleAdapter] was specified for package [foo]. Possible causes are an incorrect adapter class name or
the wrong loader has been set.]
Using package level annotation works as expected.
The largest scope you can register an XmlAdapter for in EclipseLink MOXy or any JAXB (JSR-222) implementation is the package level.
For More Information
You can read more about JAXB and package level adapters on my blog:
http://blog.bdoughan.com/2012/02/jaxb-and-package-level-xmladapters.html
I have XML like this which I get from middleware
<Example library="somewhere">
<book>
<AUTHORS_TEST>Author_Name</AUTHORS_TEST>
<EXAMPLE_TEST>Author_Name</EXAMPLE_TEST>
</book>
</Example>
What I want to do is convert the XML to Java object(and Vice Versa) as:
class Example
{
private String authorsTest;
private String exampleTest;
}
So Is there any way to map these two,The thing to be noted is that XML Tag Name and the Class attribute name is different,So can anyone suggest to implement this with minimal changes?Xstream is a good Choice,but if I have large number of fields it will be difficult to add aliases,so any better choices other than XStream?
What you are looking for is called XML Binding, where you actually turn an xml into a java class based on an xml schema. The reference implementation for this is jaxb but there are many other alternatives.
There are good libraries which does this for you. An easy one is XStream for example.
See this example from the Two Minute Tutorial:
Person joe = new Person("Joe", "Walnes");
joe.setPhone(new PhoneNumber(123, "1234-456"));
joe.setFax(new PhoneNumber(123, "9999-999"));
Now, to convert it to XML, all you have to do is make a simple call to XStream:
String xml = xstream.toXML(joe);
The resulting XML looks like this:
<person>
<firstname>Joe</firstname>
<lastname>Walnes</lastname>
<phone>
<code>123</code>
<number>1234-456</number>
</phone>
<fax>
<code>123</code>
<number>9999-999</number>
</fax>
</person>
I would prefer XStream because it is very easy to use. If you want to do more complex things like generating Java classes from the XML you should have a look at JAXB as Miquel mentioned. But it is more complex and needs more time to get started.
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.
Most XML-binding libraries require an object per level of nesting in the XML representation. EclipseLink JAXB (MOXy) has the #XmlPath extension that enables XPath based mapping to remove this restriction.
Example
Below is a demonstration of how the #XmlPath extension can be applied to your use case.
package forum10511601;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement(name="Example")
#XmlAccessorType(XmlAccessType.FIELD)
class Example {
#XmlAttribute
private String library;
#XmlPath("book/AUTHORS_TEST/text()")
private String authorsTest;
#XmlPath("book/EXAMPLE_TEST/text()")
private String exampleTest;
}
jaxb.properties
To specify MOXy as your JAXB provider you need to add a file named jaxb.properties in the same package as your domain model with the following entry (see Specifying EclipseLink MOXy as Your JAXB Provider).
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Demo
As MOXy is a JAXB (JSR-222) implementation, you use the standard JAXB runtime APIs (which are included in the JRE/JDK starting with Java SE 6).
package forum10511601;
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Example.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum10511601/input.xml");
Example example = (Example) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(example, System.out);
}
}
input.xml/Output
<?xml version="1.0" encoding="UTF-8"?>
<Example library="somewhere">
<book>
<AUTHORS_TEST>Author_Name</AUTHORS_TEST>
<EXAMPLE_TEST>Author_Name</EXAMPLE_TEST>
</book>
</Example>
Given a scenario:
I have my own system's object structure. Now there are more than one XML sources I have to map to my java classes. And there is no need to convert Java object back into XML.
What's your suggestion for me to use Digester or JAXB? Currently I lean to use Digester, because I can specify XML path for each XML source to the same object method call, and Digester seems to be easier to maintain. Although JAXB has good design to marshal/unmarshal java and XML, but I think it is too complicated, xml schema is needed for each xml-java mapping, right?
I think both Digester or JAXB has their mission to fit different usage scenario, so need your advice to help me decide one of them. Thanks a lot.
I think you may have a skewed view of JAXB. It can be complicated, if you choose to make it so, but it can also be extremely simple. For example, you can bind an entire XML document onto an object graph with only a single annotation.
Also, the schema thing is a red herring. JAXB can generate java code from an XML Schema, but that's just a convenience for cases where you have a schema. If you don't, then ignore that part. You can annotate your class model by hand, it's very easy.
Digester, on the other hand, is harder to maintain (in my opinion), since you have to muck about with path expressions ion addition to your class model.
An advantage of JAXB is that it is a spec (JSR-222) with multiple implementations: Metro, EclipseLink MOXy, JaxMe. This avoids the problem of vendor lock in.
XPath Based Mapping
The EclipseLink JAXB (MOXy) has an extension to support XPath based mapping (I'm the tech lead).
package blog.geocode;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement(name="kml")
#XmlType(propOrder={"country", "state", "city", "street", "postalCode"})
public class Address {
#XmlPath("Response/Placemark/ns:AddressDetails/ns:Country/ns:AdministrativeArea/ns:SubAdministrativeArea/ns:Locality/ns:Thoroughfare/ns:ThoroughfareName/text()")
private String street;
#XmlPath("Response/Placemark/ns:AddressDetails/ns:Country/ns:AdministrativeArea/ns:SubAdministrativeArea/ns:Locality/ns:LocalityName/text()")
private String city;
#XmlPath("Response/Placemark/ns:AddressDetails/ns:Country/ns:AdministrativeArea/ns:AdministrativeAreaName/text()")
private String state;
#XmlPath("Response/Placemark/ns:AddressDetails/ns:Country/ns:CountryNameCode/text()")
private String country;
#XmlPath("Response/Placemark/ns:AddressDetails/ns:Country/ns:AdministrativeArea/ns:SubAdministrativeArea/ns:Locality/ns:PostalCode/ns:PostalCodeNumber/text()")
private String postalCode;
}
Multiple XML Sources
To apply multiple XML representations to an object model you can leverage MOXy's XML metadata. This is another extension to the JAXB standard. An example file looks like:
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="blog.bindingfile">
<xml-schema
namespace="http://www.example.com/customer"
element-form-default="QUALIFIED"/>
<java-types>
<java-type name="Customer">
<xml-root-element/>
<xml-type prop-order="firstName lastName address phoneNumbers"/>
<java-attributes>
<xml-element java-attribute="firstName" name="first-name"/>
<xml-element java-attribute="lastName" name="last-name"/>
<xml-element java-attribute="phoneNumbers" name="phone-number"/>
</java-attributes>
</java-type>
<java-type name="PhoneNumber">
<java-attributes>
<xml-attribute java-attribute="type"/>
<xml-value java-attribute="number"/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
For more information:
http://bdoughan.blogspot.com/2010/09/xpath-based-mapping-geocode-example.html
http://bdoughan.blogspot.com/2010/07/xpath-based-mapping.html
http://bdoughan.blogspot.com/2010/12/extending-jaxb-representing-annotations.html
Maybe off topic: I've abandonded digester in favor of xstream. Maybe have a look