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

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>

Related

How to bind element of namespace with EclipseLink MOXy?

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>

Issue with jaxb moxy when using binder to unmarshal xml with namespace

I m using jaxb moxy to unmarshal a xml from binder but it gives exception:A descriptor with default root element beans was not found in the project. im also using package-info.java to specify namespace.
Xml file to unmarshal-
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.example.org/package">
</beans>
Beans.java-
#XmlRootElement(namespace="http://www.example.org/package")
public class Beans {
String name = "ss";
#XmlElement
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package-info.java
#XmlSchema(
namespace="http://www.example.org/package",
elementFormDefault=XmlNsForm.QUALIFIED)
package com.jaxb.test;
import javax.xml.bind.annotation.*;
Main class-
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
File xml = new File(
"D:\\eclipse-jee-indigo-SR2\beans.xml");
Document document = db.parse(xml);
JAXBContext jc = JAXBContext.newInstance(Beans.class);
Binder<Node> binder = jc.createBinder();
Beans customer = (Beans) jc.createBinder().unmarshal(document);//throws exception
//Beans customer = (Beans) jc.createUnmarshaller().unmarshal(xml);This works
//Beans customer = (Beans) jc.createUnmarshaller().unmarshal(document);Throws same exception
Exception-
javax.xml.bind.UnmarshalException
- with linked exception:
[Exception [EclipseLink-25008] (Eclipse Persistence Services - 2.4.1.v20121003- ad44345): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: A descriptor with default root element beans was not found in the project]
at org.eclipse.persistence.jaxb.JAXBUnmarshaller.handleXMLMarshalException(JAXBUnmarshaller.java:1014)
at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:199)
at com.jaxb.test.JaxbTest.main(JaxbTest.java:43)
By default a DocumentBuilderFactory is not namespace aware. This means the document you are passing to MOXy will not be namespace qualified as expected. You can fix this by adding the following to your code:
dbf.setNamespaceAware(true);
Solved It.Instead of using a package-info.java i used bindins.xml .
beans-bindings.xml-
<?xml version="1.0" encoding="UTF-8"?>
<xml-schema element-form-default="QUALIFIED" namespace="http://www.example.org/package">
<xml-ns prefix="" namespace-uri="http://www.example.org/package" />
</xml-schema>
<java-types>
<java-type name="Beans">
<xml-root-element name="beans"/>
<java-attributes>
</java-attributes>
</java-type>
</java-types>

Marshalling collections when using XmlElementWrapper

I have a collection on my class that uses #XmlElementWrapper to wrap the collection in a extra element.
So, my class looks something like this:
class A {
#XmlElement(name = "bee")
#XmlElementWrapper
public List<B> bees;
}
And my XML then looks something like:
<a>
<bees>
<bee>...</bee>
<bee>...</bee>
</bees>
</a>
Great, this is what I wanted. However, when I try and marshall into JSON, I get this:
{
"bees": {
"bee": [
....
]
}
}
And I don't want that extra "bee" key there.
Is it possible to somehow have MOXy ignore the XmlElement part when doing this marshalling? because I still need the name to be "bees" and not "bee", and I don't want both.
I'm using MOXy 2.4.1 and javax.persistence 2.0.0.
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
oxm.xml
You could use MOXy's external mapping document to provide an alternate mapping for your JSON-binding (see: http://blog.bdoughan.com/2010/12/extending-jaxb-representing-annotations.html).
<?xml version="1.0"?>
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="forum14002508">
<java-types>
<java-type name="A">
<java-attributes>
<xml-element java-attribute="bees" />
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
Demo
In the demo code below we will create two instances of JAXBContext. The first is build solely on the JAXB annotations that we will use for XML. The second is built on the JAXB annotations and uses MOXy's external mapping file to override the mapping for the bees property on the A class.
package forum14002508;
import java.util.*;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.JAXBContextProperties;
public class Demo {
public static void main(String[] args) throws Exception {
List<B> bees = new ArrayList<B>();
bees.add(new B());
bees.add(new B());
A a = new A();
a.bees = bees;
JAXBContext jc1 = JAXBContext.newInstance(A.class);
Marshaller marshaller1 = jc1.createMarshaller();
marshaller1.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller1.marshal(a, System.out);
Map<String, Object> properties = new HashMap<String, Object>(3);
properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, "forum14002508/oxm.xml");
properties.put(JAXBContextProperties.MEDIA_TYPE, "application/json");
properties.put(JAXBContextProperties.JSON_INCLUDE_ROOT, false);
JAXBContext jc2 = JAXBContext.newInstance(new Class[] {A.class}, properties);
Marshaller marshaller2 = jc2.createMarshaller();
marshaller2.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller2.marshal(a, System.out);
}
}
Output
Below is the output from running the demo code that matches your use case.
<a>
<bees>
<bee/>
<bee/>
</bees>
</a>
{
"bees" : [ {
}, {
} ]
}
For More Information
http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html
http://blog.bdoughan.com/2011/08/json-binding-with-eclipselink-moxy.html

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>

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