2010-11-10 5 views
36

Ich versuche, eine Liste von Objekten zu erstellen, die eine gemeinsame Schnittstelle implementieren. Es gibt drei Klassen und 1-Schnittstelle beteiligt: ​​Marshalling einer Liste von Objekten, die eine gemeinsame Schnittstelle implementieren, mit JaxB

Gemeinschaft Klasse (hat eine Methode: Liste <Person> getPeople();)

Person Schnittstelle (hat eine Methode: String getName();)

Mädchen Klasse (implementiert Person)

Junge Klasse (implementiert Person)

Siehe Code unten.

Ich möchte eine XML, die etwa wie folgt aussieht:

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

oder möglicherweise:

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

weit Also, was ich bekommen, ist dies:

<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> 

Ich weiß, ich kann ändere das Element in etwas anderes, aber ich möchte, dass der Elementname der Name ist, der in der Girl- oder Boy-Klasse angegeben ist.

Kann dies getan werden? Vielen Dank.

@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; 
    } 

} 

Antwort

44

Für dieses Szenario würde ich die Verwendung von @XmlElements empfehlen. @XmlElements wird verwendet, um das XML-Schema-Konzept der Wahl darstellen:

Hier ist, wie es für Ihr Beispiel aussehen:

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

@XmlElementRef entspricht das Konzept Substitutionsgruppen im XML-Schema. Aus diesem Grund muss in der vorherigen Antwort Person von einer Schnittstelle in eine Klasse geändert werden.

12

OK, wenn Sie bereit sind, Person von einer Schnittstelle in eine abstrakte Basisklasse zu ändern, dann sind Sie golden. Hier ist der Code:

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(); 
} 

Der wichtigste Trick war der Einsatz von @XmlElementRef in der Liste der Gemeinschaft. Dies identifiziert den Typ der Klasse durch ihr @ XmlRootElement. Sie könnten auch an der @XmlSeeAlso interessiert sein, die hilft, Kontextdeklarationen zu organisieren.

Und der Ausgang ist

<?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> 
Verwandte Themen