2017-01-26 5 views
0

Я пытаюсь unmarshall Xml возвращен из остального вызова в POJO. Однако один вызов может возвращать различные типы документов с различными корневыми элементами, например.Jaxb unmarshall в зависимости от корневого элемента

<obj1> ... </obj1> 
<obj2> ... </obj2> 

Я распаковать с помощью обобщенной функции:

private <T> T unmarshal(String xml, Class<T> clazz) { 
    JAXBContext jc = JAXBContext.newInstance(clazz); 
    return clazz.cast(jc.createUnmarshaller().unmarshal(new StringReader(xml)); 
} 

Я создал для отдельных классов для каждого из различных корней, но я не знаю, как я могу проверить тип корневого элемента и затем вызовите функцию unmarshall с правильным типом?

if rootElement.equals("obj1") 
    Obj1 obj = unmarshal(xml, Obj1.class) 
else if rootElement.equals("obj2") 
    Obj2 obj = unmarshal(xml, Obj2.class) 

Есть ли способ использовать JaxB для выполнения этой условной проверки на корневом элементе?

ответ

0

да можно.

  1. Объявите каждый из возможных классов корня @XmlRootElement.
  2. Создайте JAXBContext со всеми возможными корневыми классами, как показано ниже.

    JAXBContext jc = JAXBContext.newInstance(Class...)

  3. Затем

    Object obj = unmarshal(xml); if(obj instanceof Root1) { // cast to Root1 object } else obj instanceof Root2) { // cast to Root2 object }

0

Я не знаю, если есть лучший способ сделать это, но я не нашел. Чтобы решить эту проблему, я создал объект, который содержит оба типа корневых элементов:

@Data 
public class compositionObject { 
private Obj1 obj1; 
private Obj2 obj2; 

public compositionObject(final Object obj) { 
    if(obj instanceof Obj1) { 
     this.obj1 = obj1; 
    } else if(obj instanceof Obj2) { 
     this.obj2 = obj2; 
    } else { 
     throw new IllegalArgumentExcepion("not supported"); 
    } 
} 

Для маршализации в поле родовым образом:

private Object unmarshal(String xml, Class<?>... clazzes) { 
    JAXBContext jc = JAXBContext.newInstance(clazzes); 
    return clazz.cast(jc.createUnmarshaller().unmarshal(new StringReader(xml)); 
} 

Использование @XmlRegistry с @XmlElementDecl не дает мне предполагаемое поведение поскольку он вернет JAXBElement<Obj1> вместо JAXBElement<CompositionObject>. Следующий не работает:

private final static QName OBJ1_QNAME = new QName("", "obj1"); 
private final static QName COMP_OBJ_QNAME = new QName("", "compositionobj"); 

@XmlElementDecl(namespace = "", name = "obj1") 
public JAXBElement<CompositionObject> createObj1(final Obj1 value) { 
    final CompositionObject compObj = new CompositionObject(); 
    comPbj.setObj1(value); 
    return new JAXBElement<CompositionObject>(COMP_OBJ_QNAME, CompositionObject.class, null, value); 
} 

Вопрос: @XmlRegistry - how does it work? ответов почему @XmlRegistry не может быть использована таким образом.

+0

'@ XmlRootElement' достаточно, чтобы вы получили правильный экземпляр объекта после unmarshalling. Я думаю, проблема в том, что вы не разделили их как '@ XmlRootElement'. Может быть, вы можете подробно объяснить, почему вы не можете приложить к объекту корневого элемента напрямую, используя пункт 3 выше в моем ответе? – ulab

+0

Оба класса модели Obj1 и Obj2 аннотируются с помощью «@XmlRootElement». Я полагаю, что постановка задачи несколько неоднозначна. Я хотел написать логику логического анализа, чтобы он мог принимать несколько «@XmlRootElement» и преобразовывать их в один объект. Я хотел сделать это, потому что вызов, который я делал во внешнюю службу REST, может возвращать разные типы объектов для одного и того же вызова. – Niru