XML annotations (JAXB) suggestions for unmarshalling and marshalling - java

I have a sample XML as shown below:
<?xml version="1.0" encoding="UTF-8"?>
<Education>
<School name="ABC" location="Mangalore">
<Student gender="M" housepincode="575020">
<FirstName>VJ</FirstName>
<LastName>K</LastName>
</Student>
<Student gender="M" housepincode="575002">
<FirstName>S</FirstName>
<LastName>K</LastName>
</Student>
</School>
</Education>
This has been unmarshalled with the help of JAXB using the following approach.
I have classes for Education,School and Student.
Education.java
import lombok.Data;
#Data
#XmlRootElement(name = "Education")
public class Education {
public School School;
}
School.java
import lombok.Data;
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class School {
#XmlAttribute
private String name;
#XmlAttribute
private String location;
#XmlElement(name ="Student")
private List<Student> Student;
}
Student.java
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class Student {
#XmlAttribute
private String gender;
#XmlAttribute
private String housepincode;
#XmlElement(name = "FirstName")
private String FirstName;
#XmlElement(name = "LastName")
private String LastName;
}
I have some concerns over the output I receive. First of all there are some warnings. I believe it is because i have missed some annotations which should be present. Any suggestions or guidance here please?
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.sun.xml.bind.v2.runtime.reflect.opt.Injector (file:/C:/Users/R.Premsagar/.m2/repository/org/glassfish/jaxb/jaxb-runtime/2.3.0-b170127.1453/jaxb-runtime-2.3.0-b170127.1453.jar) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int)
WARNING: Please consider reporting this to the maintainers of com.sun.xml.bind.v2.runtime.reflect.opt.Injector
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
Education(School=School(name=ABC, location=Mangalore, Student=[Student(gender=M, housepincode=575020, FirstName=VJ, LastName=K), Student(gender=M, housepincode=575002, FirstName=S, LastName=K)]))
Also, the heirarchy of output does not seem correct to me, Eg: School = School tag?
I want to print this output to a separate XML to verify the result.
However the script fails
Main program:
List<Education> Entries = new ArrayList<Education>();
try {
File xmlFile = new File("Withattributes.xml");
JAXBContext jaxbContext;
jaxbContext = JAXBContext.newInstance(Education.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Education entries = (Education) jaxbUnmarshaller.unmarshal(xmlFile);
Entries.add(entries); //storing objects in a list for later use
//--------------------------------------------------------------
JAXBContext jaxbContext_w = JAXBContext.newInstance(Education.class);
Marshaller jaxbMarshaller = jaxbContext_w.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
jaxbMarshaller.marshal(jaxbContext_w, System.out);
}
catch (JAXBException e)
{
e.printStackTrace();
} catch (FactoryConfigurationError e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I get the following error message:
Neither the class com.sun.xml.bind.v2.runtime.JAXBContextImpl nor one of the associated superclasses is known to this context.
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getBeanInfo(JAXBContextImpl.java:593)
at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:482)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:328)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:256)
at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:110)
at JaxbExample.main(JaxbExample.java:39)
Please let me know what could be done here..
UPDATE:
If the XML is updated to have a structure as below:
<?xml version="1.0" encoding="UTF-8"?>
<Education>
<School name="ABC" location="Mangalore">
<Student gender="M" housepincode="575020">
<FirstName>VJ</FirstName>
<LastName>K</LastName>
<Hobbies>
<Hobby time = "M">Novels</Hobby>
<Hobby time = "A">Gaming</Hobby>
</Hobbies>
</Student>
</School>
</Education>
Now the class of Student.java would change to
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class Student {
#XmlAttribute
private String gender;
#XmlAttribute
private String housepincode;
#XmlElement(name = "FirstName")
private String FirstName;
#XmlElement(name = "LastName")
private String LastName;
#XmlElementWrapper(name ="Hobbies")
#XmlElement(name="Hobby")
private List<Hobby> Hobbies;
}
and the Hobby.java
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class Hobby{
#XmlAttribute(name="Time")
private String Time;
#XmlElement
private String Hobby;
}
With this modification I do not get the value of the Hobby tag. I get the list of Hobbies and values something like this:
Hobbies>
<Hobby time = "M"/>
<Hobby time = "A"/>
</Hobbies>
Could you correct me here please?

First issue:
I am no expert on JAXB so I do not have much idea on what could cause the warnings specified here but I tried following the code and it seems to work fine for me without any warnings. If you want to get more understanding then the best thing to do is search about it and read the doc to get more information. But my guess is that it's happening due to your second issue.
Also, I am using Moxy which is an extension of JAXB developed by Eclipse-link. It has many additional benefits compared to simple JAXB
Second issue:
obvious error is in this line:
jaxbMarshaller.marshal(jaxbContext_w, System.out);
why are you providing jaxbContext_w as an input to it. It should be the unmarshalled values. In your case, it is entries.
Following is the complete code:
Education:
#Data
#XmlRootElement(name = "Education")
#XmlAccessorType(XmlAccessType.FIELD)
public class Education {
public School School;
}
School:
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class School {
#XmlAttribute
private String name;
#XmlAttribute
private String location;
#XmlElement
private List<Student> Student;
}
Student:
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class Student {
#XmlAttribute
private String gender;
#XmlAttribute
private String housepincode;
#XmlElement
private String FirstName;
#XmlElement
private String LastName;
}
Main:
public class Main {
public static void main(String[] args) throws JAXBException, XMLStreamException {
final InputStream inputStream = Main.class.getClassLoader().getResourceAsStream("students.xml");
final XMLStreamReader xmlStreamReader = XMLInputFactory.newInstance().createXMLStreamReader(inputStream);
final Unmarshaller unmarshaller = JAXBContext.newInstance(Education.class).createUnmarshaller();
final Education education = unmarshaller.unmarshal(xmlStreamReader, Education.class).getValue();
System.out.println(education.toString());
Marshaller marshaller = JAXBContext.newInstance(Education.class).createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(education, System.out);
}
}
Output (Without any error or warnings):
Education(School=School(name=ABC, location=Mangalore, Student=[Student(gender=M, housepincode=575020, FirstName=VJ, LastName=K), Student(gender=M, housepincode=575002, FirstName=S, LastName=K)]))
<Education>
<School name="ABC" location="Mangalore">
<Student gender="M" housepincode="575020">
<FirstName>VJ</FirstName>
<LastName>K</LastName>
</Student>
<Student gender="M" housepincode="575002">
<FirstName>S</FirstName>
<LastName>K</LastName>
</Student>
</School>
</Education>

Related

Mapping xml attributes to java attributes

Is there a way to map xml attributes to Java attributes using Jackson Faster xml.
Sample xml
<student>
<details>
<element key="firstName" value="John" />
<element key="lastName" value="Doe" />
</details>
</student>
The above xml needs to be mapped to below Java class.
public class Student {
private String firstName;
private String lastName;
}
for such cases, I have written a static piece of code:
public static <T> T unmarshall(String xml, Class<T> clazz) throws JAXBException {
JAXBContext jc = JAXBContext.newInstance(clazz);
Unmarshaller unmarshaller = jc.createUnmarshaller();
T obj = clazz.cast(unmarshaller.unmarshal(new StringReader(xml)));
return obj;
}
Also annotate your DTO with:
#Getter
#Setter
#XmlRootElement(name = "<SomeName>")
#XmlAccessorType(XmlAccessType.FIELD)
public class Student {
private String firstName;
private String lastName;
}
After you have this method, you can use it to serialize your data:
Student studentResponse = (Student) unmarshall(response, Student.class);

Create XML string in java with custom namespace

I want to generate xml string in java programmatically whose name space is custom as shown below
and all data must come dynamically in xml.How can I achieve something like this?
<faxml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="test.xsd">
<person>
<name>ABC</name>
</person>
</faxml>
I have gone through examples like this https://howtodoinjava.com/jaxb/write-object-to-xml/ but here when xml generated its starting line is
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
but I want start and end tag <faxml> and namespaces as I mentioned in my sample code as output
Here is one approach:
First, here is my class representing the required XML data:
package org.ajames.jaxb.persons;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "")
#XmlRootElement(name = "faxml")
public class Faxml {
private Person person;
public static class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
}
I chose to nest the Person class inside the root class - just for this test. There are other ways to arrange these classes, of course, so they are not nested.
Then I define the package-info for org.ajames.jaxb.persons as follows:
#XmlSchema(
namespace = "",
elementFormDefault = XmlNsForm.UNSET,
xmlns = {
#XmlNs(prefix = "", namespaceURI = "http://www.w3.org/2001/XMLSchema-instance")
})
package org.ajames.jaxb.persons;
import javax.xml.bind.annotation.XmlSchema;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
To process the data from a Java object to XML, I use the following test data:
Faxml.Person person = new Faxml.Person();
person.setName("ABC");
Faxml faxml = new Faxml();
faxml.setPerson(person);
The JAXB context and marshaller are as follows, assuming we are writing the XML to a Java String, for this test:
JAXBContext jaxbContext = JAXBContext.newInstance(Faxml.class);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION, "test.xsd");
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
StringWriter stringWriter = new StringWriter();
marshaller.marshal(faxml, stringWriter);
String xml = stringWriter.toString();
System.out.println(xml);
The resulting XML is:
<faxml xsi:noNamespaceSchemaLocation="test.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<person>
<name>ABC</name>
</person>
</faxml>
String name= "name"
String createXml="<faxml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"//
xsi:noNamespaceSchemaLocation="test.xsd">"//
+"<person>"//
+"<name>"+name+"</name>"//
+"</>person">"//
+"</faxml>";
Sysout(createXml);
get the name in a variable. Hard code these lines and insert it like this..

java JAXB save subclass when saving

I'm struggling saving all data from my class/subclass using JAXB.
I want to save all accounts from an observableList, but the problem is, the account class
public class Account{
private ObjectProperty<HosterObject> host;
....
}
contains an HosterObject which has 2 attributes:
publicName and privateName also have getter and setter.
#XmlRootElement(name = "hoster")
public class HosterObject {
private final StringProperty publicName;
private final StringProperty privateName;
public HosterObject(String publicName, String privateName){
this.publicName = new SimpleStringProperty(publicName);
this.privateName = new SimpleStringProperty(privateName);
}
#XmlElement(name = "publicName")
public StringProperty publicNameProperty(){
return publicName;
}
#XmlElement(name = "privateName")
public StringProperty privateNameProperty(){
return privateName;
}
How can I save the content from the Hosterobject as Element in the xml-file as well?
At the moment the xml file looks so:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<accounts>
<account>
<hoster/>
<password>123</password>
<status>unchecked</status>
<username>test</username>
</account>
</accounts>
But i should look kinda like this
...
<account>
<hoster>
<publicName>Name</publicName>
<privateName>private Name</privateName>
</hoster>
....
</account>
....
The code for saving:
public void saveAccountDataToFile(File file) {
try {
JAXBContext context = JAXBContext.newInstance(AccountListWrapper.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
// Wrapping our person data.
AccountListWrapper wrapper = new AccountListWrapper();
wrapper.setAccounts(accountData);
// Marshalling and saving XML to the file.
m.marshal(wrapper, file);
} catch (Exception e) {
}
}
Wrapper:
#XmlRootElement(name = "accounts")
public class AccountListWrapper {
private List<Account> accounts;
#XmlElement(name = "account")
public List<Account> getAccounts() {
return accounts;
}
public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
}
Thanks in advance!
Add:
tag HosterObject by
#XmlRootElement(name = "hoster")
#XmlElement
for class and set method for HosterObject in Account.
public HosterObject (){}
public Account(){}
JAXB need default empty constructor.
If you want to add class to xml you must tag it and create always default public constructor. Remember to tag only class which are non abstract.

Write pojo class for this xml file

I'm getting null value when unmarshelling the xml file to java class. But the xml file as values corresponding to the its attributes. Is there any mistake in my pojo class or unmarshelling?
Please help
This is my pojo
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "")
#XmlRootElement(name = "CardUpdateResponse",namespace="http://www.samople.com/Prepaid")
public class FVCardUpdateResponse {
#XmlElement(name = "AccountNumber")
private String AccountNumber;
#XmlElement(name = "ResCode")
private String ResCode;
#XmlElement(name = "ResErrorCode")
private String ResErrorCode;
#XmlElement(name = "ResErrorMsg")
private String ResErrorMsg;
//Setters and Getters
}
This is my xml file
<?xml version="1.0" encoding="UTF-8"?>
<CardUpdateResponse xmlns="http://www.samople.com/Prepaid">
<CARDUPDATE_RET>
<ResErrorMsg>ID Issue Date must be equal or less than present date</ResErrorMsg>
<ResErrorCode>ErrIsud01</ResErrorCode>
<ResCode>0</ResCode>
<ACCOUNTNUMBER>2000000003918246</ACCOUNTNUMBER>
</CARDUPDATE_RET>
</CardUpdateResponse>
this is code for unmarshelling
public class XmlUnmarshelling {
public void unmarshell()
{
try
{
System.out.println("xml unmarshelling class");
File file = new File("D:/var/lib/tomcat7/webapps/tmpFiles/1.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(FVCardUpdateResponse.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
FVCardUpdateResponse CARDUPDATE_ret = (FVCardUpdateResponse) jaxbUnmarshaller.unmarshal(file);
System.out.println("xml unmarshelled = "+CARDUPDATE_ret.getResErrorMsg());//Getting null value as response.
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
Your POJO doesn't have the same structure as your XML. CardUpdateResponse doesn't directly contain the properties in your POJO, it contains CARDUPDATE_RET element which contains the properties.
You could modify your POJO like this to match the XML:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "CardUpdateResponse", namespace="http://www.samople.com/Prepaid")
public static class CardUpdateResponseWrapper {
#XmlElement(name="CARDUPDATE_RET")
private FVCardUpdateResponse response;
// Getter and setter for response
public static class FVCardUpdateResponse {
#XmlElement(name = "AccountNumber")
private String AccountNumber;
#XmlElement(name = "ResCode")
private String ResCode;
#XmlElement(name = "ResErrorCode")
private String ResErrorCode;
#XmlElement(name = "ResErrorMsg")
private String ResErrorMsg;
// Getters and setters
}
}
Now the CardUpdateResponseWrapper class will represent your root XML element and it will have instance of FVCardUpdateResponse which will represent the CARDUPDATE_RET XML element.
Do unmarshall it, just call:
File file = new File("D:/var/lib/tomcat7/webapps/tmpFiles/1.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(CardUpdateResponseWrapper.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
CardUpdateResponseWrapper wrapper = (CardUpdateResponseWrapper) jaxbUnmarshaller.unmarshal(file);
System.out.println(wrapper.getResponse().getResErrorMsg());
I think that the issue is a combination of two problems, one what Bohuslav is saying, the other you need to repeat your namespace on every XmlElement annotation, e.g.
#XmlElement(name = "ResCode", namespace="http://www.samople.com/Prepaid")
and one particular issue, you need to match the cases as well so the name for AccountNumber should be capitalized ACCOUNTNUMBER

Default namespace & complex package/data structure

I need create/read xml file using default namespace:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xmlBoo xmlns="http://www.example2.org/boo">
<customer>
<address>
<street>Wall Street</street>
</address>
<id>1</id>
<name>John</name>
</customer>
<someSpecificField>Specific data in Boo</ns2:someSpecificField>
</xmlBoo>
but I'm getting:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:xmlBoo xmlns:ns2="http://www.example2.org/boo">
<ns2:customer>
<address>
<street>Wall Street</street>
</address>
<id>1</id>
<name>John</name>
</ns2:customer>
<ns2:someSpecificField>Specific data in Boo</ns2:someSpecificField>
</ns2:xmlBoo>
I know about package level metadata, but this is not working in complex package structure:
I have defined model classes like Address:
package example.model;
public class Address {
private String street;
Customer:
package example.model;
public class Customer {
private long id;
private String name;
private Address address;
The parent class for common fields:
package example.xml;
#XmlTransient
public class Xml {
private Customer customer;
Then specific classes which holds data/structure of concrete xml XmlBoo:
package example.xml.boo;
#XmlRootElement
public class XmlBoo extends Xml {
private String someSpecificField;
XmlFoo:
package example.xml.foo;
#XmlRootElement
public class XmlFoo extends Xml {}
package-info.java is included in two mentioned packages example.xml.boo:
#XmlSchema(
namespace = "http://www.example2.org/boo",
elementFormDefault = XmlNsForm.QUALIFIED)
package example.xml.boo;
and example.xml.foo:
#XmlSchema(
namespace = "http://www.example2.org/foo",
elementFormDefault = XmlNsForm.QUALIFIED)
package example.xml.foo;
And finally main method:
package example;
public class Demo {
public static void main(String... args) {
generateBoo();
generateFoo();
}
public static void generateBoo() {
try {
JAXBContext jc = JAXBContext.newInstance(XmlBoo.class);
Marshaller m = jc.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
XmlBoo xmlBoo = new XmlBoo();
Customer customer = new Customer();
customer.setId(1);
customer.setName("John");
Address address = new Address();
address.setStreet("Wall Street");
customer.setAddress(address);
xmlBoo.setCustomer(customer);
xmlBoo.setSomeSpecificField("Specific data in Boo");
m.marshal(xmlBoo, System.out);
} catch (JAXBException e) {
e.printStackTrace();
}
}
public static void generateFoo() {
try {
JAXBContext jc = JAXBContext.newInstance(XmlFoo.class);
Marshaller m = jc.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
XmlFoo xmlFoo = new XmlFoo();
Customer customer = new Customer();
customer.setId(1);
customer.setName("John");
Address address = new Address();
address.setStreet("Wall Street");
customer.setAddress(address);
xmlFoo.setCustomer(customer);
m.marshal(xmlFoo, System.out);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
I've tried both solutions like here and also without success.
It is possible remove & rename prefix if I have all classes in one package (and one package-info file)
It is possible rename but NOT remove prefix if I have complex package structure
Is there solution how I can remove ns2 prefix?
I'm using JDK7.
Solution how get (write & read xml) the needed result:
<?xml version="1.0" encoding="UTF-8"?>
<xmlBoo xmlns="http://www.example.org/boo" xmlns:c="http://www.example.org/customer" xmlns:a="http://www.example.org/address" xmlns:h="http://www.example.org/header">
<h:header>
<h:id>101</h:id>
</h:header>
<c:customer>
<c:id>1</c:id>
<c:name>Yen</c:name>
<a:address>
<a:street>Long street</a:street>
</a:address>
</c:customer>
<someBooSpecificField>Specific data in Boo</someBooSpecificField>
</xmlBoo>
for root element and its "simple" children is used default namespace (without prefix)
for complex (objects in java) children are used different namespaces (mapped to different prefixes)
model classes are in different packages
So here is the solution:
Define MOXy implementation of JAXB, file: jaxb.properties
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Create abstract class for common fields, define namespace for object, file Xml.java
package example.xml;
#XmlTransient
public abstract class Xml {
private Header header;
private Customer customer;
#XmlElement(namespace="http://www.example.org/header")
public Header getHeader() {
return header;
}
public void setHeader(Header header) {
this.header = header;
}
#XmlElement(namespace="http://www.example.org/customer")
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
Create "root" class, XmlBoo.java
package example.xml.boo;
#XmlRootElement
#XmlType(propOrder = {"header", "customer", "someBooSpecificField"})
public class XmlBoo extends Xml {
private String someBooSpecificField;
// getter & setter
}
Set namespace and QUALIFIED for "root" class, file: example.xml.boo.package-info.java
#XmlSchema(
namespace = "http://www.example.org/boo",
elementFormDefault = XmlNsForm.QUALIFIED)
package example.xml.boo;
Set QUALIFIED to generate prefix for children (the namespace will be overridden by namespace defined on the class, but it must be defined), file: example.model.package-info.java
#XmlSchema(
namespace = "http://www.example.org",
elementFormDefault = XmlNsForm.QUALIFIED)
package example.model;
Create Header.java
package example.model;
#XmlType(namespace = "http://www.example.org/header")
public class Header {
private long id;
// getter & setter
}
Create Customer.java
package example.model;
#XmlType(namespace = "http://www.example.org/customer", propOrder = {"id", "name", "address"})
public class Customer {
private long id;
private String name;
private Address address;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#XmlElement(namespace="http://www.example.org/address")
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
Create Address.java
package example.model;
#XmlType(namespace = "http://www.example.org/address")
public class Address {
private String street;
// getter & setter
}
Create MyNamespacePrefixMapper.java by extending org.eclipse.persistence.oxm.NamespacePrefixMapper
package example;
import org.eclipse.persistence.oxm.NamespacePrefixMapper;
public class MyNamespacePrefixMapper extends NamespacePrefixMapper {
private static final String BOO_PREFIX = ""; // DEFAULT NAMESPACE
private static final String BOO_URI = "http://www.example.org/boo";
private static final String FOO_PREFIX = ""; // DEFAULT NAMESPACE
private static final String FOO_URI = "http://www.example.org/foo";
private static final String HEADER_PREFIX = "h";
private static final String HEADER_URI = "http://www.example.org/header";
private static final String CUSTOMER_PREFIX = "c";
private static final String CUSTOMER_URI = "http://www.example.org/customer";
private static final String ADDRESS_PREFIX = "a";
private static final String ADDRESS_URI = "http://www.example.org/address";
#Override
public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
switch (namespaceUri) {
case BOO_URI:
return BOO_PREFIX;
case FOO_URI:
return FOO_PREFIX;
case HEADER_URI:
return HEADER_PREFIX;
case CUSTOMER_URI:
return CUSTOMER_PREFIX;
case ADDRESS_URI:
return ADDRESS_PREFIX;
default:
return null;
}
}
}
Create XML
public static void generateBoo() {
try {
JAXBContext jc = JAXBContext.newInstance(XmlBoo.class);
Marshaller m = jc.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
m.setProperty(MarshallerProperties.NAMESPACE_PREFIX_MAPPER, new MyNamespacePrefixMapper());
XmlBoo xmlBoo = new XmlBoo();
Header header = new Header();
header.setId(101);
xmlBoo.setHeader(header);
Customer customer = new Customer();
customer.setId(1);
customer.setName("Yen");
Address address = new Address();
address.setStreet("Long street");
customer.setAddress(address);
xmlBoo.setCustomer(customer);
xmlBoo.setSomeBooSpecificField("Specific data in Boo");
m.marshal(xmlBoo, System.out);
m.marshal(xmlBoo, new File("xml_boo.xml"));
} catch (JAXBException e) {
e.printStackTrace();
}
}
Read XML
public static void readBoo() {
Object element = null;
try {
JAXBContext jc = JAXBContext.newInstance(XmlBoo.class);
Unmarshaller u = jc.createUnmarshaller();
element = u.unmarshal(new File("xml_boo.xml"));
} catch (JAXBException e) {
e.printStackTrace();
}
if (element instanceof XmlBoo) {
XmlBoo xmlBoo = (XmlBoo) element;
Customer customer = xmlBoo.getCustomer();
System.out.println("INFO | xmlBoo field: [" + xmlBoo.getSomeBooSpecificField() + "]");
System.out.println("INFO | customer name: [" + customer.getName() + "]");
System.out.println("INFO | address street: [" + customer.getAddress().getStreet() + "]");
}
}
I used EclipseLink MOXy JAXB implementation instead of RI Metro JAXB and now it works. So it looks that in Metro is bug.
Perfect tutorial by Blaise Doughan: JAXB & Namespace prefixes
You will need to have a package-info annotation with a #XmlSchema annotation for each package in your domain model each specifying the same namespace qualification to get the desired XML.

Categories

Resources