Дублированное поле в сгенерированном XML с использованием JAXB - PullRequest
8 голосов
/ 21 октября 2011

Это мой сценарий. У меня есть общий класс:

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;
  }
}

и детский класс:

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;
  }
}

Эти классы упоминаются здесь:

@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;
  }
}

Затем создается объект Relation с чем-то вроде:

Relation rel = new Relation();
rel.setRelationVars(new Tuple<StringTuple>(
  new StringTuple("RelationshipVar1"), new StringTuple("RelationshipVar2")));

После упорядочивания этого объекта вывод XML будет следующим:

<?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>

Итак, элементы value дублированы !.

Теперь причина, по которой класс StringTuple переопределяет List<T> getList() на List<String> getList(), заключается в том, что избегает надоедливых сгенерированных атрибутов xmlns:xs в каждом члене списка (элементы value в документе xml). Но тогда каждый член списка отображается дважды в выводе. По-видимому, это связано с тем, что как переопределенный родительский метод, так и дочерний метод помечены @XmlElement. Итак, мой главный вопрос: есть ли способ игнорировать переопределенные методы, помеченные @XmlElement в Jaxb? (учитывая, что метод переопределения также помечен @XmlElement)

Я обнаружил, что в старом сообщении довольно похожая проблема: http://old.nabble.com/@XmlElement-on-overridden-methods-td19101616.html, но я пока не нашел решения. Также обратите внимание, что добавление аннотации @XmlTransient к методу getList в родительском классе (Tuple<T>) может решить эту проблему, но создаст другие, поскольку родительский класс не является абстрактным и используется отдельно в других контекстах.

Односторонний вторичный вопрос: возможно ли объявить атрибут xmlns:xs в корневом узле вместо того, чтобы он - раздражающе - появлялся в каждом узле, где он необходим? Я знаю, что это можно сделать с помощью класса NamespacePrefixMapper, но, поскольку это нестандартный внутренний класс SUN, я предпочитаю использовать более независимый от реализации подход.

Заранее спасибо за любые отзывы!

Ответы [ 2 ]

3 голосов
/ 21 октября 2011

Вы можете использовать следующий подход для пометки свойства @XmlTransient на родительском элементе и @XmlElement на дочернем:

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);
    }

}

Демо

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);
    }

}

Выход

<?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 голосов
/ 14 ноября 2013

Это может быть довольно старым, но это первый результат при поиске "JAXB дубликаты полей"

Наткнулся на ту же проблему, это помогло мне:

@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE) // <-- made the difference
public abstract class ParentClass
{
...
}


@XmlRootElement
public class ChildClass extends ParentClass
{
 ...
}
...