Duplicated field in generated XML using JAXB

谁说我不能喝 提交于 2019-12-06 23:29:23

问题


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 !


回答1:


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>



回答2:


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
{
 ...
}


来源:https://stackoverflow.com/questions/7851052/duplicated-field-in-generated-xml-using-jaxb

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!