2015-10-16 2 views
0

Мне нужно отобразить следующий XML-объект, основанный на значении типа элемента. Суперкласс класса BaseEntity имеет общие элементы для классов Machine и Robot. В каждом подклассе есть разные элементы ... Структура XML исправлена, и я не могу ее изменить. Каждый элемент ввода должен быть сопоставлен с соответствующим классом, entry/type = Машина должна быть сопоставлена ​​с подклассом Machine и т. Д.Подкласс JAXB Unmarshal, основанный на значении дочернего элемента

Возможно ли в JAXB? Как я могу это реализовать? Любое предложение?

<root> 
    <entries> 
     <entry> 
      <name>RTM</name> 
      <description>RealTime Machine</description> 
      <code>RTM1</code> 
      <type>Machine</type> 
     </entry> 
     <entry> 
      <name>RTM</name> 
      <description>RealTime Machine</description> 
      <type>Robot</type> 
      <serial>RS123<serial> 
     </entry> 
    </entries> 
</root> 

public abstract class BaseEntity { 
    private String name; 
    private String description; 
} 
public class Machine extends BaseEntity{ 
    private String code; 
} 
public class Robot extends BaseEntity{ 
    private String serial; 
} 
+0

Если вам не все равно о производительности, отключите все дочерние классы и выберите один на основе значения 'type'. –

+0

Да, я. Документ представляет собой схему диаграммы, которая может прибыть до 1000 записей, мне нужно загрузить его быстрее. Другое решение? – s0d

ответ

1

К сожалению, ваш XML-макет действительно плохой. Когда парсер JAXB входит в узел ввода, он не может определить узлом, является ли он роботом или другим роботом. Поэтому он должен угадать, какой тип использовать для размаширования. Обычно вы должны использовать тип как имя узла (1) или предоставлять атрибут с параметром type (2).

1:

<entries> 
    <machine>...</machine> 
    <robot>...</robot> 
</entries> 

2:

<entries> 
    <entry type="machine">...</entry> 
    <entry type="robot">...</entry> 
</entries> 

Так что мое решение вашей проблемы, как Франкенштейн, как ваш XML.

Есть адаптированный класс, который расширяет базовый класс и имеет все атрибуты доступных подклассов:

@XmlRootElement(name = "ENTRY") 
@XmlAccessorType(XmlAccessType.FIELD) 
public class AdaptedBaseEntry extends BaseEntry 
{ 


    @XmlElement(name = "CODE", required = false) 
    public String code; 

    @XmlElement(name = "SERIAL", required = false) 
    public String serial; 

    public AdaptedBaseEntry() 
    { 
     super(); 
    } 

    public AdaptedBaseEntry(BaseEntry entry) 
    { 
     super(entry.type, entry.description, entry.name); 
     if (entry instanceof Machine) 
     { 
      this.code = ((Machine) entry).code; 
     } else if (entry instanceof Robot) 
     { 
      this.serial = ((Robot) entry).serial; 
     } 
    } 

} 

Используйте XmlAdapter привязать класс адаптера к XML и наоборот:

public class BaseEntryAdapter extends XmlAdapter<AdaptedBaseEntry, BaseEntry> 
{ 

    @Override 
    public BaseEntry unmarshal(AdaptedBaseEntry v) throws Exception 
    { 
     switch (v.type) 
     { 
     case Machine: 
      return new Machine(v.name, v.description, v.code); 
     case Robot: 
      return new Robot(v.name, v.description, v.serial); 
     default: 
      return null; 
     } 
    } 

    @Override 
    public AdaptedBaseEntry marshal(BaseEntry v) throws Exception 
    { 
     return new AdaptedBaseEntry(v); 
    } 

}