«Поскольку я не могу изменить входной XML, есть ли что-нибудь еще, что я могу сделать, с помощью комментариев Джексона, Джексона XML или JAXB?»
Я не очень хорошо знаком с функциями Xml от Jackson. Но с JAXB Unmarshaller
и небольшим изменением аннотаций это может быть достигнуто.
Для вашего List<AbstractPojo>
вы можете использовать @XmlAnyElement(lax = true)
.
С lax = true
:
Если верно, когда элемент соответствует свойству помеченного XmlAnyElement
известно JAXBContext
(например, есть класс с XmlRootElement, который имеет такое же имя тега, или есть XmlElementDecl
, что имеет то же самое имя тега), то unmarshaller охотно распаковать этот элемент объекта JAXB, а демаршаллизации его DOM
которые в основном означает, что если мы аннотирования PojoA
и PojoB
с @XmlRootElement
и передать имя элемента в качестве атрибута name
(@XmlRootElement(name = "a")
), по определению это должно работать.
Давайте дадим ему шанс:
public abstract class AbstractPojo {
// note this class is not annotated. It will be known in the context
// as we're explicitly using the type int the Root class
}
@XmlRootElement(name = "a")
public class PojoA extends AbstractPojo {
}
@XmlRootElement(name = "b")
public class PojoB extends AbstractPojo {
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "root")
public class Root {
@XmlAnyElement(lax = true)
protected List<AbstractPojo> objects;
public List<AbstractPojo> getObjects() {
if (objects == null) {
objects = new ArrayList<>();
}
return this.objects;
}
}
Используя следующий файл XML, чтобы проверить
<?xml version="1.0" encoding="UTF-8"?>
<root>
<a/> <b/> <b/> <a/> <a/> <b/> <b/>
</root>
И следующая тестовая программа
public class JaxbTest {
private static final String FILE_NAME = "test.xml";
public static void main(String[] args) throws Exception {
JAXBContext context = JAXBContext.newInstance(Root.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
File f = new File(FILE_NAME);
Root root = (Root)unmarshaller.unmarshal(f);
List<AbstractPojo> list = root.getObjects();
for (AbstractPojo p : list) {
System.out.print(p instanceof PojoA ? "a " : "b ");
}
System.out.println();
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
Мы получаем результат мы находимся находясь в поиске.
a b b a a b b
// вместе с содержимым XML-файла мы мобилизовывать для тестирования
Вот некоторые хорошие ресурсы:
UPDATE
Хорошо, я понимаю, почему вы получали ElementNSImpl
. Это не работает для меня, я получаю объекты ElementNSImpl. Вы знаете, что происходит?
Да, я вижу, что происходит. Во-первых, я скомпилировал xsd с xjc, и он создал ObjectFactory для меня, который объявил элементы. Вот почему это работает для меня.
Если вы этого не сделаете, вы должны явно помещать PojoA
и PojoB
в контекст.
JAXBContext.newInstance(Root.class, PojoA.class, PojoB.class);
Это не работает для меня , Я получаю объекты ElementNSImpl. Вы знаете, что происходит? Я добавлю свое решение тем временем –
Пожалуйста, см. Мое ** ОБНОВЛЕНИЕ **. Также вы не могли бы опубликовать, как это реализовано с помощью '@ XmlElements/@ XmlElementRefs'. Я не смог заставить его работать. –