Использование JAXB для сортировки узла XML, который может содержать только один из нескольких типов дочерних узлов (запрос SharePoint)

Я пытаюсь создать аннотированные классы JAXB для создания XML на основе Microsoft SharePoint Схема запроса. У меня есть класс SpWhereClause:

@XmlType(name="Where")
@XmlAccessorType(XmlAccessType.FIELD)
public class SpWhereClause {

}

Но я не уверен, как структурировать/аннотировать его свойства. У элемента <Where> может быть много различных типов дочерних элементов (<Eq>, <BeginsWith>, <Contains> и т. д. Давайте пока проигнорируем <And> и <Or>), но не более одного. Eq и BeginsWith являются отдельно допустимыми дочерними элементами Where, но это не может быть так:

<Where>
    <Eq>...</Eq>
    <BeginsWith>...</BeginsWith>
</Where>

без вложения <Eq> и <BeginsWith> в элемент <Or>.

Моей первой мыслью было создать класс AbstractSpComparison с элементами <FieldRef> и <Value>, общими для всех сравнений:

@XmlAccessorType(XmlAccessType.FIELD)
public abstract class AbstractSpComparison {

    @XmlElement
    private SpFieldRef fieldRef;

    @XmlElement
    private SpValue value;

    ...
}

затем попросите SpEqualsComparison расширить его:

@XmlType(name="Eq")
public class SpEqualsComparison extends AbstractSpComparison {

}

Однако использование абстрактного класса в SpWhereClause не позволяет мне контролировать имя дочернего элемента. Этот:

@XmlElement
private AbstractSpComparison comparison;

Результаты в этом:

<Where>
    <comparison>...</comparison>
</Where>

вместо этого:

<WHERE>
    <Eq>...</Eq>
</WHERE>

Почему имя «Eq» из SpEqualsComparison не используется для названия элемента сравнения? Как правильно поступить в такой ситуации?

Я рассматривал возможность использования всех возможных типов дочерних элементов в качестве свойства SpWhereClause и устанавливал только тот, который мне нужен (где-то с некоторой логикой проверки), но это кажется излишне подробным.

Если это важно, я использую Пружина ОХМ Jaxb2Marshaller.


person Dave    schedule 11.06.2014    source источник


Ответы (1)


Есть несколько вариантов, которые вы можете сделать:

Вариант №1 – @XmlElementRef

Если все расширяет общий суперкласс (например, AbstractSpComparison), вы можете использовать аннотацию @XmlElementRef. Когда вы сделаете это, дочерний элемент будет соответствовать значению аннотации @XmlRootElement в классе объекта, на который делается ссылка.

@XmlElementRef
private AbstractSpComparison comparison;

Для получения дополнительной информации

Я написал больше об этом подходе в своем блоге:

Вариант №2 - @XmlElements

Если все не расширяет общий суперкласс, вы можете использовать аннотацию @XmlElements, где вы явно аннотируете, какие элементы могут отображаться и какому классу они соответствуют:

@XmlElements({
    @XmlElement(name="Eq", type=Eq.class),
    @XmlElement(name="BeginsWith", type=BeginsWith.class)
})
private AbstractSpComparison comparison;

Для получения дополнительной информации

Я написал больше об этом подходе в своем блоге:

person bdoughan    schedule 11.06.2014
comment
Спасибо! Это именно то, что мне было нужно. Я выбрал вариант 1, но думаю, что вариант 2 пригодится в некоторых других ситуациях. - person Dave; 14.06.2014