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

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>

Related

Adding namespaces to root element of xml using jaxb

I am creating an xml file whose root elemenet structure shuould be like:
<RootElement xmlns="http://www.mysite.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mysite.com/abc.xsd">
i created package-info.java class but i can get only one namespace by writing this code:
#XmlSchema(
namespace = "http://www.mysite.com",
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package myproject.myapp;
import javax.xml.bind.annotation.XmlSchema;
Any idea?
Below is some demo code that will produce the XML you are looking for. You can use the Marshaller.JAXB_SCHEMA_LOCATION property to specify the schemaLocation this will cause the http://www.w3.org/2001/XMLSchema-instance namespace to be automatically declared.
Demo
package myproject.myapp;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(RootElement.class);
RootElement rootElement = new RootElement();
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "http://www.mysite.com/abc.xsd");
marshaller.marshal(rootElement, System.out);
}
}
Output
Below is the output from running the demo code.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<RootElement xmlns="http://www.mysite.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mysite.com/abc.xsd"/>
package-info
This is the package-info class from your question.
#XmlSchema(
namespace = "http://www.mysite.com",
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED
)
package myproject.myapp;
import javax.xml.bind.annotation.*;
RootElement
Below is a simplified version of your domain model:
package myproject.myapp;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name="RootElement")
public class RootElement {
}
In the older Jaxb you can specify additional namespaces using #XmlSeeAlso and in the newer Jaxb you can use #XmlNs in package-info.java see this answer: https://stackoverflow.com/a/63559294/447503

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