How to override JAXB #XMLAccessorType(XMLAccessType.FIELD) specified at a Class level with #XMLElement on a getter method for a property? - jaxb

In the example code below, Employee class has been specified with JAXB field level access type. For the property dept, however, the access type has been specified at getter method level with #XMLElement annotation.
During marshalling of Organization class, the following exception is thrown -
com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
Class has two properties of the same name "dept"
this problem is related to the following location:
at public java.lang.String com.playground.jaxb.Employee.getDept()
this problem is related to the following location:
at private java.lang.String com.playground.jaxb.Employee.dept
Can you help me understand why this overriding of JAXB accessor type is not working please? Also any solution would be highly appreciated.
Example
Root Element Class
package com.playground.jaxb;
#XMLRootElement(name="organization")
public class Organization {
#XmlElementWrapper(name = "employees")
#XmlElement(name = "employee")
private Set<Employee> employees;
public Organization{}
// Remainder omitted...
}
Employee Class
package com.playground.jaxb;
#XMLAccessorType(XMLAccessType.FIELD)
public class Employee {
private String name;
private String dept;
#XMLElement(name="department")
public String getDept() {
return dept;
}
public void setDept(String dept) {
this.dept = dept;
}
public Employee {}
// Remainder omitted...
}

You can re-name getter/setter pair, e.g. getDept() -> getDepartment()
private String dept;
#XmlElement(name="department")
public String getDeptartment() {
return dept;
}
public void setDeptartment(String dept) {
this.dept = dept;
}
but in this case you will have duplicate in XML
<dept>my_dept</dept>
<department>my_dept</department>
Or you can annotate field dept with #XmlTransient annotation, if you want to change access type it.
#XmlTransient
private String dept;
#XmlElement(name="department")
public String getDept() {
return dept;
}
public void setDept(String dept) {
this.dept = dept;
}
In this case, dept field will be ignored and getter/setter pair will be used instead

Related

JAXB dynamic XML root class name

I have my User class in java. When I want to unmarshal it, I get xml with <UserIn> root element, and when I want to marshal it I should do <UserOut> to be XML root element. If I provide #XmlRootElement("UserIn") it is not dynamic and it is always UserIn root. Is there any way to do dynamic root element on class? thanks.
You could create two classes that extend your User class, and then use the specific child class based on if you are marshalling on unmarshalling.
For example, for a class User:
public class User {
#XmlElement
private String value;
public User() { }
public User(String value) {
this.value = value;
}
}
You can have UserIn:
#XmlRootElement(name = "UserIn")
#XmlAccessorType(XmlAccessType.FIELD)
public class UserIn extends User {
public UserIn() { }
public UserIn(String value) {
super(value);
}
}
and UserOut:
#XmlRootElement(name = "UserOut")
#XmlAccessorType(XmlAccessType.FIELD)
public class UserOut extends User {
public UserOut() { }
public UserOut(String value) {
super(value);
}
}
Provide the appropriate class where you need, and you will get it working with the input or output you wish.

Why is XStream ignoring #XmlTransient?

Does XStream handle JAXB #XmlTransient attributes by default? XStream seems to be ignoring the #XmlTransient attribute & serializing the field anyway.
In the sample code below. ExampleClass2 is getting serialized even though I don't want it to be. Further details are that these classes are being populated by OpenJPA.
XStream Code
XStream _x0 =null;
_x = XStreamImpl.getInstance();
_x.toXML(_object)
Class I want to serialize
#DataCache
#Entity
public class ExampleClass implements Serializable {
private short defaultOption;
private int primaryKey;
private short orderId;
#XmlTransient
private ExampleClass2 _exampleClass2;
#XmlTransient
public ExampleClass2 getTblPpwsCommCfgCombo() {
return _exampleClass2;
}
#XmlTransient
public void setExampleClass2(ExampleClass2 _exampleClass2) {
this._exampleClass2 = _exampleClass2;
}
public short getDefaultOption() {
return defaultOption;
}
public void setDefaultOption(short defaultOption) {
this.defaultOption = defaultOption;
}
public short getPrimaryKey() {
return primaryKey;
}
public void setPrimaryKey(int primaryKey) {
this.primaryKey = primaryKey;
}
public short getOrderId() {
return orderId;
}
public void setOrderId(short orderId) {
this.orderId = orderId;
}
}
You can use the #Transient annotation or transiet key word:
#Transient
private ExampleClass2 _exampleClass2;
~

jaxb marxshalling - duplicate elements in the xml

I have two objects that are in hierarchical relationship. I have the jaxb mapping for setter methods in the child pojo. While loading the xml into pojo I don't have any issues. However, while generating the xml, I see two element entries in the xml for the same attribute in pojo the object - one with the mapping key and the other with actual variable name.
Example:
//parent class
public class Employee {
private String name;
public String getName(){
return this.name;
}
public void setName(String name){
this.name=name;
}
}
//second class
#XmlRootElement(name = "teacher")
public class Teacher extends Employee {
#Override
public String getName(){
return super.getName();
}
#Override
#XmlElement(name ="NAME")
public void setName(String name){
super.setname(name)
}
}
//xml out put I get is
// like this
<teacher>
<name>John Doe<name/>
<NAME>John Doe</NAME>
</teacher>
How do I fix this? I want just the one with the key - NAME
You could do either:
Mark the name property on the Emoloyee class as #XmlTransient.
Mark the Employee class as #XmlTransient to remove it as a mapped class.
Remove the name property from the Teacher class and annotate the one on Employee with your #XmlElement annotation.

JAXB Marshalling: Creating an empty element with an attribute

I use a JAXB marshaller and I would like to add an empty element with a specific attribute. This is a dummy class:
#XmlRootElement(name="observation")
public class Observation {
#XmlAttribute
public static final String classCode = "OBS";
#XmlAttribute
public static final String moodCode = "EVN";
private String data;
#XmlElement
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
This creates the following XML:
<observation classCode="OBS" moodCode="EVN">
<data>fsdfsdfd</data>
</observation>
Is there any way to add a new element with a specific attribute only (no value at all)? E.g.
<observation classCode="OBS" moodCode="EVN">
<templateId root="2.16.840.1.113883.10.20.1.31"/>
<data>fsdfsdfd</data>
</observation>
This should do it:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "TemplateIdType")
public class TemplateIdType {
#XmlAttribute(name = "root")
protected String root;
// getter and setter
}
(And you add an element of this class to Observation.)

Marshall object field as attribute

Here is what I have so far to marshall my POJO using JAXB :
#XmlRootElement
public class Local {
private Entity entity;
public void setEntity(Entity entity) {
this.entity = entity;
}
#XmlElement
public Entity getEntity() {
return entity;
}
}
and
#XmlRootElement
public class Entity {
private String name;
private String comment;
public void setName(String name){
this.name = name;
}
#XmlAttribute
public String getName(){
return this.name;
}
public void setComment...
#XmlAttribute
public void getComment...
}
With that, I get something like this:
<local>
<entity name="" comment=""></entity>
</local>
However, I would prefer to have the name attribute as an attribute of the local:
<local entityName="" entityComment=""></local>
Is the XmlJavaTypeAdapter a good way to begin with?
Thanks,
Alex
There are a couple of different options to handle this use case:
Option #1 - XmlAdapter (Any JAXB implementation)
You could use an XmlAdapter for this use case. This will work as long as only one attribute value comes from the Entity object:
EntityAdapter
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class EntityAdapter extends XmlAdapter<String, Entity>{
#Override
public String marshal(Entity entity) throws Exception {
if(null == entity) {
return null;
}
return entity.getName();
}
#Override
public Entity unmarshal(String name) throws Exception {
Entity entity = new Entity();
entity.setName(name);
return entity;
}
}
Local
The XmlAdapter is linked with the field/property using the #XmlJavaTypeAdapter annotation:
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
#XmlRootElement
public class Local {
private Entity entity;
public void setEntity(Entity entity) {
this.entity = entity;
}
#XmlAttribute
#XmlJavaTypeAdapter(EntityAdapter.class)
public Entity getEntity() {
return entity;
}
}
For More Information
http://blog.bdoughan.com/2010/07/xmladapter-jaxbs-secret-weapon.html
http://blog.bdoughan.com/2010/12/jaxb-and-immutable-objects.html
Option #2 - #XmlPath (EclipseLink JAXB (MOXy)
Alternatively if you are using EclipseLink JAXB (MOXy), the you could use the #XmlPath extension. This is useful with the Entity object corresponds to multiple XML attributes:
Local
Specifying the XPath "." indicated that the child contents will be written into the parent element
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.*;
#XmlRootElement
public class Local {
private Entity entity;
public void setEntity(Entity entity) {
this.entity = entity;
}
#XmlPath(".")
public Entity getEntity() {
return entity;
}
}
Entity
public class Entity {
private String name;
private String comment;
public void setName(String name){
this.name = name;
}
#XmlAttribute(name="entityName")
public String getName(){
return this.name;
}
public void setComment(String comment){
this.comment = comment;
}
#XmlAttribute(name="entityComment")
public String getComment(){
return this.comment;
}
}
For More Information
http://bdoughan.blogspot.com/2010/07/xpath-based-mapping.html
http://blog.bdoughan.com/2010/09/xpath-based-mapping-geocode-example.html
http://blog.bdoughan.com/2011/03/map-to-element-based-on-attribute-value.html
http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html

Resources