2010-11-10 2 views
36

Я пытаюсь сортировать список объектов, реализующих общий интерфейс. Есть 3 класса и 1 интерфейс участвуют:Маршаллинг Список объектов, реализующих общий интерфейс, с JaxB

сообщества класс (имеет один метод: Список <Person> getPeople();)

Person интерфейс (имеет один метод: Строка GetName();)

Девушка класс (реализующий Person)

Boy класс (реализующий Person)

См ниже код.

Я хочу XML, который выглядит примерно так:

<community> 
    <people> 
    <girl> 
     <name>Jane</name> 
    </girl> 
    <boy> 
     <name>John</name> 
    </boy> 
    <girl> 
     <name>Jane</name> 
    </girl> 
    <boy> 
     <name>John</name> 
    </boy> 
    </people> 
</community> 

или, возможно:

<community> 
    <people> 
    <person> 
     <girl> 
     <name>Jane</name> 
     </girl> 
    </person> 
    <person> 
     <boy> 
     <name>John</name> 
     </boy> 
    </person> 
    </people> 
</community> 

Пока что я получаю это:

<community> 
    <people> 
     <person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="girl"> 
      <name>Jane</name> 
     </person> 
     <person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="boy"> 
      <name>John</name> 
     </person> 
     <person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="girl"> 
      <name>Jane</name> 
     </person> 
     <person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="boy"> 
      <name>John</name> 
     </person> 
    </people> 
</community> 

Я понимаю, что могу измените элемент на что-то еще, но я хочу, чтобы имя элемента было названо именем класса в классе Girl or Boy.

Можно ли это сделать? Благодарю.

@XmlRootElement(name = "community") 
public class Community { 

private List<Person> people; 

@XmlElementWrapper 
@XmlElement(name="person") 
public List<Person> getPeople() { 
    return people; 
} 

public Community() { 
    people = new ArrayList<Person>(); 
    people.add(new Girl()); 
    people.add(new Boy()); 
    people.add(new Girl()); 
    people.add(new Boy()); 
} 
} 







@XmlRootElement(name = "girl") 
public class Girl implements Person { 

@XmlElement 
public String getName() { 
    return "Jane"; 
} 
} 


@XmlRootElement(name = "boy") 
public class Boy implements Person { 

@XmlElement 
public String getName() { 
    return "John"; 
} 
} 



@XmlJavaTypeAdapter(AnyTypeAdapter.class) 
public interface Person { 
public String getName(); 
} 



public class AnyTypeAdapter extends XmlAdapter<Object, Object> { 

@Override 
    public Object marshal(Object v) throws Exception { 
    return v; 
    } 

@Override 
    public Object unmarshal(Object v) throws Exception { 
    return v; 
    } 

} 

ответ

44

Для этого сценария я бы рекомендовал использовать @XmlElements. @XmlElements используется для представления концепции XML схемы выбора:

Вот как это выглядело бы для примера:

@XmlElements({ 
    @XmlElement(name="girl", type=Girl.class), 
    @XmlElement(name="boy", type=Boy.class) 
}) 
@XmlElementWrapper 
public List<Person> getPeople() { 
    return people; 
} 

@XmlElementRef соответствует концепции группы замещения в XML-схеме. Вот почему в предыдущем ответе персонаж должен быть изменен с интерфейса на класс.

12

ОК, если вы готовы изменить человека из интерфейса в абстрактный базовый класс, тогда вы золотой. Вот код:

public class Main { 


    public static void main(String[] args) throws Exception { 

    Community community = new Community(); 

    JAXBContext context = JAXBContext.newInstance(Community.class); 
    Marshaller marshaller = context.createMarshaller(); 
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
    marshaller.marshal(community, System.out); 

    } 
} 

@XmlRootElement(name = "community") 
@XmlSeeAlso({Person.class}) 
public class Community { 

private List<Person> people; 

@XmlElementWrapper(name="people") 
@XmlElementRef() 
public List<Person> getPeople() { 
    return people; 
} 

public Community() { 
    people = new ArrayList<Person>(); 
    people.add(new Girl()); 
    people.add(new Boy()); 
    people.add(new Girl()); 
    people.add(new Boy()); 
} 
} 

@XmlRootElement(name="boy") 
public class Boy extends Person { 

public String getName() { 
    return "John"; 
} 
} 

@XmlRootElement(name="girl") 
public class Girl extends Person { 

public String getName() { 
    return "Jane"; 
} 
} 

@XmlRootElement(name = "person") 
@XmlSeeAlso({Girl.class,Boy.class}) 
public abstract class Person { 

    @XmlElement(name="name") 
public abstract String getName(); 
} 

Основной трюк является использование @XmlElementRef в списке Сообщества. Это определяет тип класса через @XmlRootElement. Вы также можете быть заинтересованы в @XmlSeeAlso, который поможет организовать объявления контекста.

И выход

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<community> 
    <people> 
     <girl> 
      <name>Jane</name> 
     </girl> 
     <boy> 
      <name>John</name> 
     </boy> 
     <girl> 
      <name>Jane</name> 
     </girl> 
     <boy> 
      <name>John</name> 
     </boy> 
    </people> 
</community> 
Смежные вопросы