Маршал JAXB Набор‹Объект›

У меня есть объект, подобный этому:

public class Obj {
    @XmlElement(name="value")
    public Set<Object> values;
}

При маршалинге создается xml, например:

<Obj>
    <value xsi:type="xs:dateTime" xmlns:xs="http://www.w3.org/2001/XMLSchema">2009-02-14T00:31:30.001+01:00</value>
    <value xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">test</value>
</Obj>

Однако я хочу изменить некоторые из этих значений (например, формат даты, используемый для сериализации объектов Date и Timestamp), а также избавиться от надоедливых атрибутов xsi (но это не совсем обязательное требование, я могу с этим смириться)

Я пытался добавить @XmlJavaTypeAdapter к values, но в адаптере я получаю полный Set<Object> вместо отдельных элементов. Я также пытался использовать пакетный адаптер, но, поскольку мой Set предназначен для Object, я не могу поставить атрибут @XmlJavaTypeAdapter(type).

Кроме того, я пытался с помощью @XmlJavaTypeAdapter(value=MyAdapter.class, type=Timestamp.class) получить только адаптер для значений внутри этого объекта, который мне нужен.

Итак, вопрос: кто-нибудь знает, как заставить адаптер работать для этого? Или, может быть, менять формат даты каждый раз, когда объект Date или Timestamp сериализуется?

Заранее спасибо!


person Edu Garcia    schedule 10.06.2011    source источник


Ответы (1)


@XmlJavaTypeAdapter со свойством типа должно быть указано на уровне пакета. При таком использовании он указывает, что все использования этого типа в указанном пакете преобразуются с использованием XmlAdapter. Например. если у вас есть package-info.java нравится

@XmlJavaTypeAdapters({
    @XmlJavaTypeAdaptor(type=Timestamp.class, value=MyAdapter.class)
})
package org.example;

Затем класс в этом пакете с полем Timestamp.

package org.example;
public class Obj {
    public Timestamp aTimestamp;
}

Указанный адаптер будет использоваться для преобразования метки времени. Я подозреваю, что это сработает для вашего случая Set<Object>, но я сам не пробовал.

Причина атрибута xsi:type заключается в том, что JAX-B любит создавать XML, который он может десериализовать, поэтому ему нужно указать, какой это тип, иначе он мог бы анализировать все только как строки. Вы можете избавиться от этого атрибута, используя @XmlElementRef для создания группы подстановки схемы, но в этом случае XML будет создан с другими именами элементов. Например.

public class Obj {
    @XmlElementRefs({
        @XmlElementRef(type=String.class, name="string"),
        @XmlElementRef(type=Timestamp.class, name="timestamp")
    })
    public Set<Object> value;
}

Создаст следующую структуру XML, если у вас есть метка времени и строка в наборе. В этом сценарии атрибут xsi:type не нужен, так как JAX-B может сказать, какой тип создать из имени элемента.

<Obj>
    <timestamp>2009-02-14T00:31:30.001+01:00</timestamp>
    <string>test</string>
</Obj>

Я настоятельно рекомендую использовать @XmlElementWrapper, чтобы обернуть все элементы набора, если вы собираетесь использовать этот подход.

Если все, что вам нужно, — это простой набор строк, десериализацию которых вам не нужно возвращать в объекты Java (или любые другие) с правильными типами, то самое простое решение — иметь XmlAdapter, который просто адаптирует полный Set<Object> в Set<String> и займитесь преобразованием самостоятельно.

person EdC    schedule 16.06.2011
comment
К сожалению, это было первое, что я попробовал, но безуспешно. Кажется, что JAXB (или моя реализация по умолчанию) игнорирует адаптер, когда объекты находятся внутри коллекции. Кроме того, я знал о том, почему JAXB аннотирует мои поля тегами xsi, но я хотел только избавиться от них. Я не могу изменить свой XML, так как он уже используется в продукте, с которым я пытаюсь установить связь. Спасибо за ваш ответ! - person Edu Garcia; 17.06.2011
comment
В этом случае я бы предложил использовать XmlAdaptor для преобразования Set‹Object› в Set‹String› и выполнить преобразование самостоятельно. Я думаю, это единственный способ, которым это сработает. - person EdC; 20.06.2011