How to bind element of namespace with EclipseLink MOXy? - jaxb

I have the following java model:
public class Container {
public X x;
public Y y;
}
public class X {
public String test;
}
public class Y {}
and want to map the following document:
<?xml version="1.0" encoding="UTF-8"?>
<my:root xmlns:my="http://my.url" test="value">
<x/>
</my:root>
For this, I use a bindings file:
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="example">
<xml-schema namespace="http://my.url" />
<java-types>
<java-type name="Container">
<xml-root-element name="root"/>
<xml-type namespace="http://my.url" />
<java-attributes>
<xml-element java-attribute="x" xml-path="x" type="example.X"/>
<xml-element java-attribute="y" xml-path="." type="example.Y"/>
</java-attributes>
</java-type>
<java-type name="Y">
<java-attributes>
<xml-element java-attribute="test" xml-path="#test"/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
It fails with an Exception:
[Exception [EclipseLink-25008] (Eclipse Persistence Services - 2.5.1.v20130918-f2b9fc5): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: A descriptor with default root element {http://my.url}root was not found in the project]
at org.eclipse.persistence.jaxb.JAXBBinder.unmarshal(JAXBBinder.java:100)
at example.Main.main(Main.java:39)
The model for the given document is not necessarily very intuitive but neither do I have an influence on the model or the document.
How can I make it work? Everything worked fine until the namespace "http://my.url" was introduced.

Using the information you provided in your question, the following demo code works for me:
Demo Code
Demo
import java.io.File;
import java.util.*;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.JAXBContextProperties;;
public class Demo {
public static void main(String[] args) throws Exception {
Map<String, Object> properties = new HashMap<String, Object>(1);
properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, "example/oxm.xml");
JAXBContext jc = JAXBContext.newInstance(new Class[] {Container.class}, properties);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/example/input.xml");
Object result = unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(result, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8"?>
<ns0:root xmlns:ns0="http://my.url">
<x/>
</ns0:root>

Related

JAXB | MOXy | EclipseLink - The java interface com.domain.Entity can not be mapped by JAXB as it has multiple mappable parent interfaces

so I have run into a problem where I am trying to convert a complex bean structure into XML format.
I have five classes in the same package (annotated).
Each class extends an abstract class and implements an interface:
#Entity
#Table(name = SubscriptionInvoiceItemChargesImpl.TABLE_NAME)
#DataCache(enabled = false)
public class SubscriptionInvoiceItemChargesImpl extends AbstractEntityImpl implements SubscriptionInvoiceItemCharges {
Here is the abstractEntityImpl class:
public abstract class AbstractEntityImpl extends AbstractPersistenceImpl implements Entity {
Here is the Entity Interface:
public interface Entity extends PureEntity, Persistence {
}
Now, all I want is to just have the methods defined in my 5 classes (depend on each other through composition) to be written into XML and DO NOT want any data from the parent classes/interfaces.
Contents of jaxb.properties:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Here is the bindings file:
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="com.domain.ecomm.impl">
<java-types>
<java-type name="SubscriptionContactImpl" super-type="java.lang.Object"/>
</java-types>
<java-types>
<java-type name="SubscriptionInvoiceItemChargesImpl" super-type="java.lang.Object"/>
</java-types>
<java-types>
<java-type name="SubscriptionInvoiceItemImpl" super-type="java.lang.Object"/>
</java-types>
<java-types>
<java-type name="SubscriptionAccountImpl" super-type="java.lang.Object"/>
</java-types>
<java-types>
<java-type name="SubscriptionImpl" super-type="java.lang.Object"/>
</java-types>
</xml-bindings>
Here is teh marshalling code:
InputStream is = ZuoraServiceImpl.class.getClassLoader().getResourceAsStream("com/domain/ecomm/impl/subscription-bindings.xml");
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, is);
JAXBContext jc;
try {
jc = JAXBContext.newInstance(new Class[] {SubscriptionContactImpl.class}, properties);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(subscriptionContact, System.out);
} catch (JAXBException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Running the code gives me teh following error:
Exception Description: The java interface com.domain.Entity can not be mapped by JAXB as it has multiple mappable parent interfaces. Multiple inheritence is not supported]
maven dependency used:
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
<version>2.5.2</version>
</dependency>
The 'Entity' interface is in a different package than the other classes.
would appreciate any pointers.
There is a bug in the eclipselink parser, As a workarround used the jaxb.properties with content
javax.xml.bind.context.factory=com.sun.xml.internal.bind.v2.ContextFactory
the jaxb.properties must in the classpath in the same package as the class you are serializing
an other workarround is to use the version 2.6.0 of the eclipselink jaxb implementation

JaxB Xpath : How to use multiple xpath to a same java bean?

I need to generate xml using jaxb as below :
<item>
<key1 id="default">value1</key1>
<key2 id="default">value2</key2>
<key3 id="default">value3</key3>
</item>
how to do this using #XmlPath in jaxb?
i have used below one. But i have multiple keys around 50. how to acheive this?
#XmlPath("key1/#id")
private String attrValue = "default";
#XmlPath is an extension in the EclipseLink MOXy implementation of JAXB (JSR-222). You will need to use the equivalent in MOXy's mapping file to get the desired behaviour.
oxm.xml
What you are looking for is the ability to apply multiple writeable mappings for a field/property. This can't currently be done via annotations, but can be done using MOXy's external mapping document.
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="forum12704491">
<java-types>
<java-type name="Item">
<java-attributes>
<xml-element java-attribute="attrValue" xml-path="key1/#id"/>
<xml-element java-attribute="attrValue" xml-path="key2/#id" write-only="true"/>
<xml-element java-attribute="attrValue" xml-path="key3/#id" write-only="true"/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
Item
package forum12704491;
import javax.xml.bind.annotation.*;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Item {
private String attrValue;
private String key1;
private String key2;
private String key3;
}
jaxb.properties
In order to specify MOXy as your JAXB provider you need to add a file called jaxb.properties in the same package as your domain model with the following entry (see: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html)
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Demo
The demo code below demonstrates how to bootstrap using MOXy's external mapping document.
package forum12704491;
import java.io.File;
import java.util.*;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.JAXBContextProperties;
public class Demo {
public static void main(String[] args) throws Exception {
Map<String, Object> properties = new HashMap<String, Object>(1);
properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, "forum12704491/oxm.xml");
JAXBContext jc = JAXBContext.newInstance(new Class[] {Item.class}, properties);
File xml = new File("src/forum12704491/input.xml");
Unmarshaller unmarshaller = jc.createUnmarshaller();
Item item = (Item) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(item, System.out);
}
}
input.xml/Output
<?xml version="1.0" encoding="UTF-8"?>
<item>
<key1 id="default">value1</key1>
<key2 id="default">value2</key2>
<key3 id="default">value3</key3>
</item>

Jaxb EclipseLink/MOXy : Is it possible to specify the names of get/set methods

I have a quite simple question :
Say I have a model class defined like this :
public class Test{
private String testAttribute;
public Test(){
}
public String getFormattedTestAttribute(){
return testAttribute + "A nice formatted thingy"; //right, this is just an example
}
public void setTestAttribute(String value){
testAttribute = value;
}
}
You can see that I have a standard setter for testProperty but the getter has a different name : getFormattedTestProperty().
Is it possible into Jaxb/Moxy to specify which getter to use for a specific property ?
I'm using MOXy implementation with external metadata bindings file. The project which I'm working on used tu use Castor. Into Castor's mapping files, you could specify which getter/setter to use like that :
<field name="testAttribute"
get-method="getFormattedTestAttribute">
<bind-xml name="test-attribute" node="attribute"/>
</field>
Is the same kind of thing possible with moxy's external metadata ?
If that kind of customization isn't supported, is it possible to mark a field as read-only and another as write-only ? so I could declare a read-only property named "formattedTestAttribute" and a write-only property named "testAttribute" into the metadata bindings file ?
<!-- read only property -->
<xml-element java-attribute="formattedTestAttribute" xml-path="#test-attribute" />
<!-- write only property -->
<xml-element java-attribute="testAttribute" xml-path="#test-attribute" />
Please note that I have very limited control over the model classes.
Thanks in advance for your answers.
You could represent this in EclipseLink JAXB (MOXy)'s external mapping document as follows:
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="forum8834871">
<java-types>
<java-type name="Test" xml-accessor-type="PUBLIC_MEMBER">
<xml-root-element/>
<java-attributes>
<xml-element
java-attribute="testAttribute"
name="test-attribute">
<xml-access-methods
get-method="getFormattedTestAttribute"
set-method="setTestAttribute"/>
</xml-element>
<xml-transient java-attribute="formattedTestAttribute"/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
Test
I have modified your Test class, to put some logic in the get/set methods.
package forum8834871;
public class Test{
private String testAttribute;
public Test(){
}
public String getFormattedTestAttribute(){
return "APPENDED_ON_GET " + testAttribute;
}
public void setTestAttribute(String value){
testAttribute = "APPENDED_ON_SET " + value;
}
}
Demo
package forum8834871;
import java.io.File;
import java.util.*;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.JAXBContextFactory;
public class Demo {
public static void main(String[] args) throws Exception {
Map<String, Object> properties = new HashMap<String, Object>(1);
properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "forum8834871/oxm.xml");
JAXBContext jc = JAXBContext.newInstance(new Class[] {Test.class}, properties);
File xml = new File("src/forum8834871/input.xml");
Unmarshaller unmarshaller = jc.createUnmarshaller();
Test test = (Test) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(test, System.out);
}
}
input.xml
<?xml version="1.0" encoding="UTF-8"?>
<test>
<test-attribute>ORIGINAL</test-attribute>
</test>
Output
<?xml version="1.0" encoding="UTF-8"?>
<test>
<test-attribute>APPENDED_ON_GET APPENDED_ON_SET ORIGINAL</test-attribute>
</test>

JAXB-Eclipselink: Mapping abstract "getter" to XML

I am using the EclipseLink implementation (2.3) of JAXB to map POJOs to XML and encountering a problem with following usecase:
public abstract class A {
public abstract Set<X> getX();
// There is no setter
}
public class B extends A {
// Set via constructor
private Set<X> x;
#Override
public Set<X> getX();
}
I am defining the mapping itself completely in an external bindings-file, i set class A to be transient like so:
<java-type name="foo.A" xml-transient="true"/>
and for class B:
<java-type name="bar.B" xml-accessor-type="PROPERTY">
<xml-root-element name="B" />
<java-attributes>
<xml-element java-attribute="x" xml-path="..."/>
</java-attributes>
</java-type>
Now, upon marshalling i am getting the exception: "Duplicate Property named [x] found on class [bar.B]"
which in my opinion is coming from the abstract declaration in A, being inherited by B.
Setting the accessor-type for B to FIELD, gets rid of this error, unfortunately this is not an option because i do have an extra property in B to marshal which does not return a field but a calculated value, so i am stuck with PROPERTY (following works: setting accessor-type for B to FIELD and mapping the extra property with an #XmlPath annotation - but i dont want annotations in my code).
Being stuck with accessor-type PROPERTY for class B, my next attempt was:
<java-type name="foo.A" xml-accessor-type="NONE"/>
to prevent the abstract property from being inherited by B, which gets me:
Ignoring attribute [x] on class [bar.B] as no Property was generated for it.
Same is happening using this mapping:
<java-type name="foo.A" xml-accessor-type="PROPERTY">
<java-attributes>
<xml-transient java-attribute="x"/>
</java-attributes>
</java-type>
In both cases property 'x' is ignored.
I have really spent quite some time on this now - i cant imagine that its not possible to get this to work??
My workaround at the moment:
Leaving foo.A to be transient, specifying accessor-type FIELD for bar.B (which gets me property 'x' without problems) and mapping the extra property in B using an annotation in code.
But as mentioned before: I would like to solve this completely without annotations - anybody any idea? Blaise? :)
regards,
--qu
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.
You appear to have hit a bug. You can track our progress on this issue at the following link. I have provided additional details on this issue below:
https://bugs.eclipse.org/367886
Using Annotations
If you were going to map this use case with JAXB/MOXy annotations you could set #XmlAccessorType(XmlAccessType.NONE) on the A class and do something like:
A
package forum8727402;
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.NONE)
public abstract class A {
public abstract String getX();
}
B
package forum8727402;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement
public class B extends A {
#XmlPath("a/b/c/text()")
private String x;
public B() {
x = "Hello World";
}
#Override
public String getX() {
return x;
}
#XmlElement
public String getCalculatedValue() {
return "Calculated Value";
}
}
Demo
package forum8727402;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(B.class);
B b = new B();
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(b, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8"?>
<b>
<a>
<b>
<c>Hello World</c>
</b>
</a>
<calculatedValue>Calculated Value</calculatedValue>
</b>
Using MOXy's External Mapping File
oxm.xml
Below is a MOXy external mapping file that represents the equivalent of the previously shown annotations:
<?xml version="1.0" encoding="UTF-8"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="forum8727402">
<java-types>
<java-type name="A" xml-accessor-type="NONE"/>
<java-type name="B">
<xml-root-element/>
<java-attributes>
<xml-element java-attribute="x" xml-path="a/b/c/text()"/>
<xml-element java-attribute="calculatedValue"/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
Demo
The code below demonstrates how to reference the mapping file:
package forum8727402;
import java.util.*;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.JAXBContextFactory;
public class Demo {
public static void main(String[] args) throws Exception {
Map<String, Object> properties = new HashMap<String, Object>(1);
properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "forum8727402/oxm.xml");
JAXBContext jc = JAXBContext.newInstance(new Class[] {A.class, B.class}, properties);
B b = new B();
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(b, System.out);
}
}
Output
[EL Warning]: 2012-01-04 14:45:46.366--Ignoring attribute [x] on class [forum8727402.xml.B] as no Property was generated for it.
<?xml version="1.0" encoding="UTF-8"?>
<b>
<calculatedValue>Calculated Value</calculatedValue>
</b>

Implement " xml-elements" using MOXy

I want to know how to implement having List of interface Type using EclipseLink MOXy,
Before, using JAXB , The following annotations did the job
class A {
#XmlElements({
#XmlElement(name = "B1", type = B1.class),
#XmlElement(name = "B2", type = B2.class)
})
List< B > list;
}
interface B{}
class B1 implements B {}
class B2 implements B {}
to support List of interface type ???
I lead EclipseLink JAXB (MOXy). I am not able to reproduce your issue. Could you provide the stack trace you are seeing? The following is what I have tried:
Demo
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.persistence.Version;
public class Demo {
public static void main(String[] args) throws Exception {
System.out.println(Version.getVersionString());
JAXBContext jc = JAXBContext.newInstance(A.class, B1.class, B2.class);
System.out.println(jc);
File xml = new File("input.xml");
Unmarshaller unmarshaller = jc.createUnmarshaller();
JAXBElement<A> root = unmarshaller.unmarshal(new StreamSource(xml), A.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
jaxb.properties
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
input.xml
<?xml version="1.0" encoding="UTF-8"?>
<root>
<B1/>
<B2/>
</root>
Output
2.2.0.v20110202-r8913
org.eclipse.persistence.jaxb.JAXBContext#11ddcde
<?xml version="1.0" encoding="UTF-8"?>
<root>
<B1/>
<B2/>
</root>
Using EclipseLink JAXB (MOXy)'s XML Metadata File
MOXy also has an extension to provide the metadata as an XML file. Below is what it would look like for this example:
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="com.example">
<java-types>
<java-type name="A">
<java-attributes>
<xml-elements java-attribute="list">
<xml-element name="B1" type="com.example.B1"/>
<xml-element name="B2" type="com.example.B2"/>
</xml-elements>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
This metadata file is passed in as a property when the JAXBContext is created:
Map<String, Object> properties = new HashMap<String, Object>(1);
properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, new File("src/forum149/bindings.xml"));
JAXBContext jc = JAXBContext.newInstance(new Class[] {A.class, B1.class, B2.class}, properties);
For more information see:
http://bdoughan.blogspot.com/2010/12/extending-jaxb-representing-annotations.html

Resources