2010-11-10 8 views
36

Estoy tratando de identificar una lista de objetos que implementan una interfaz común. Hay 3 clases y 1 interfaz involucrados:Elaboración de una lista de objetos que implementan una interfaz común, con JaxB

Comunidad clase (tiene un método: Lista <persona> getPeople();)

persona interfaz (tiene un método: cadena getNombre();)

chica clase (implementa persona)

Chico clase (implementos Persona)

Consulte el código a continuación.

Quiero un XML que se ve algo como esto:

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

o posiblemente:

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

Hasta ahora lo que me pasa es lo siguiente:

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

que darse cuenta de lo que pueda cambia el elemento a otra cosa, pero quiero que el nombre del elemento sea el nombre especificado en la clase Girl o Boy.

¿Se puede hacer esto? Gracias.

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

} 

Respuesta

44

Para este escenario, le recomendaría el uso de @XmlElements. @XmlElements se utiliza para representar el concepto de esquema XML de elección:

Aquí es cómo se vería por su ejemplo:

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

@XmlElementRef se corresponde con el concepto de grupos de sustitución en el esquema XML. Esta es la razón por la cual la respuesta previa requiere que la Persona sea cambiada de una interfaz a una clase.

12

OK, si está preparado para cambiar a Persona de una interfaz a una clase base abstracta, entonces está satisfecho. Aquí está el código:

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

El truco principal fue el uso de @XmlElementRef en la lista de la Comunidad. Esto identifica el tipo de la clase a través de @XmlRootElement. También puede interesarle el @XmlSeeAlso que ayuda a organizar las declaraciones de contexto.

Y la salida es

<?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> 
Cuestiones relacionadas