This is my scenario. I have a generic class:
public class Tuple<T> extends ArrayList<T> {
//...
public Tuple(T ...members) {
this(Arrays.asList(members));
}
@XmlElementWrapper(name = "tuple")
@XmlElement(name = "value")
public List<T> getList() {
return this;
}
}
And a child class:
public class StringTuple extends Tuple<String> {
public StringTuple(String ...members) {
super(members);
}
//explanation of why overriding this method soon ...
@XmlElementWrapper(name = "tuple")
@XmlElement(name = "value")
@Override
public List<String> getList() {
return this;
}
}
These classes are referenced here:
@XmlRootElement(namespace = "iv4e.xml.jaxb.model")
public class Relation {
private Tuple<StringTuple> relationVars;
//...
@XmlElementWrapper(name = "allRelationVars")
@XmlElement(name = "relationVarsList")
public Tuple<StringTuple> getRelationVars() {
return relationVars;
}
}
Then a Relation object is created with something like:
Relation rel = new Relation();
rel.setRelationVars(new Tuple<StringTuple>(
new StringTuple("RelationshipVar1"), new StringTuple("RelationshipVar2")));
After marshalling this object, the Xml output is the following:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:relation xmlns:ns2="iv4e.xml.jaxb.model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="">
<allRelationVars>
<relationVarsList>
<tuple>
<value xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">RelationshipVar1</value>
</tuple>
<tuple>
<value>RelationshipVar1</value>
</tuple>
</relationVarsList>
<relationVarsList>
<tuple>
<value xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">RelationshipVar2</value>
</tuple>
<tuple>
<value>RelationshipVar2</value>
</tuple>
</relationVarsList>
</allRelationVars>
</ns2:relation>
So the value
elements are duplicated!.
Now, the reason the class StringTuple overrides List<T> getList()
with List<String> getList()
is avoiding the annoying generated xmlns:xs
attributes in every member of the list (the value
elements in the xml document).
But then every member of the list is shown twice in the output. Apparently, it is because both the overridden parent method and the child method are annotated with @XmlElement
.
So my main question is: there is a way to ignore overridden methods annotated with @XmlElement
in Jaxb ? (considering that the overridding method is also annotated with @XmlElement
)
I found an old post reporting quite a similar problem: http://old.nabble.com/@XmlElement-on-overridden-methods-td19101616.html , but I have not found any solution yet.
Also note that adding a @XmlTransient
annotation to the getList
method at the parent class (Tuple<T>
) could solve this problem but will generate others, since the parent class is not abstract and is used alone in other contexts.
One side secondary question: is it possible to declare the xmlns:xs
attribute at the root node instead of it -annoyingly- appearing in every node where it is needed? I know this can be done with the NamespacePrefixMapper
class, but since it is a non standard, SUN internal class, I rather prefer to use a more implementation independent approach.
Thanks in advance for any feedback !
This might be quite old, but its the first result while searching for "JAXB duplicate fields"
Stumbled upon the same problem, this did the trick for me:
@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE) // <-- made the difference
public abstract class ParentClass
{
...
}
@XmlRootElement
public class ChildClass extends ParentClass
{
...
}
You could use the following approach of marking the property @XmlTransient
on the parent and @XmlElement
on the child:
Parent
package forum7851052;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
@XmlRootElement
public class Parent<T> {
private List<T> item = new ArrayList<T>();
@XmlTransient
public List<T> getItem() {
return item;
}
public void setItem(List<T> item) {
this.item = item;
}
}
IntegerChild
package forum7851052;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class IntegerChild extends Parent<Integer> {
@Override
@XmlElement
public List<Integer> getItem() {
return super.getItem();
}
@Override
public void setItem(List<Integer> item) {
super.setItem(item);
}
}
StringChild
package forum7851052;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class StringChild extends Parent<String> {
@Override
@XmlElement
public List<String> getItem() {
return super.getItem();
}
@Override
public void setItem(List<String> item) {
super.setItem(item);
}
}
Demo
package forum7851052;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Parent.class, IntegerChild.class, StringChild.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
IntegerChild integerChild = new IntegerChild();
integerChild.getItem().add(1);
integerChild.getItem().add(2);
marshaller.marshal(integerChild, System.out);
StringChild stringChild = new StringChild();
stringChild.getItem().add("A");
stringChild.getItem().add("B");
marshaller.marshal(stringChild, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<integerChild>
<item>1</item>
<item>2</item>
</integerChild>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<stringChild>
<item>A</item>
<item>B</item>
</stringChild>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With