viernes, 6 de septiembre de 2013

JAXB. Realizando XML de una Lista de objetos

Si hemos seguido los ejemplos anteriores  de como obtener ficheros XML a partir de objetos y como obtener objetos a partir de ficheros XML que vimos en los dos post anteriores (aquí y aquí), ya conocemos un poco sobre el Marshalling y Unmarshalling de este tipo de componentes.
Ahora vamos a ir complicando un poco el tema. Vamos a crearnos una tabla que se llama direcciones y que está relacionada con la tabla clientes, de modo que podemos guardar varias direcciones asociadas a un mismo cliente. Nos crearemos por lo tanto la siguiente tabla en PostgreSQL junto con su relación:
DROP SEQUENCE IF EXISTS direccion_seq;
create sequence direccion_seq;
DROP TABLE IF EXISTS "direccion" CASCADE;
CREATE TABLE "direccion" (
id int default nextval('direccion_seq') primary key,
"calle" varchar(80),
"codpostal" varchar(5),
"localidad" varchar(20),
"pais" varchar(15),
"telf1" varchar(13),
"telf2" varchar(13),
"fax" varchar(13),
"email1" varchar(50),
"email2" varchar(50),
"cliente_id" int NOT NULL
) WITHOUT OIDS;
ALTER TABLE "direccion" ADD CONSTRAINT "direccion_cliente_fk" FOREIGN KEY ("cliente_id") REFERENCES cliente("id") ON UPDATE RESTRICT ON DELETE RESTRICT;
Y además introduciremos varias direcciones asociadas a los dos clientes:
insert into direccion (calle, codpostal, localidad, pais, telf1, telf2, fax, email1, email2, cliente_id) values ('Del suspiro 34', '01234', 'Cáceres', 'España', '91234235', '91234236', '912356789', 'jose@j.com', 'pedro@p.com', 1)
insert into direccion (calle, codpostal, localidad, pais, telf1, telf2, fax, email1, email2, cliente_id) values ('Oración 25', '56789', 'Badajoz', 'España', '95432123', '96789943', '95432567', 'juan@j.com', 'juanpedro@p.com', 1)
insert into direccion (calle, codpostal, localidad, pais, telf1, telf2, fax, email1, email2, cliente_id) values ('Hostia 98', '23456', 'Cuenca', 'España', '9876543', '9754321', '97654343', 'pedro@p.com', 'matias@p.com', 2)
Ahora vamos a crearnos la entity que mapea esta clase:
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlRootElement;

@Entity
@SequenceGenerator(
    name="direccion_seq",
    sequenceName="direccion_seq",
    initialValue=1,
    allocationSize=1
)

@XmlRootElement
@Table(name = "direccion")
public class Direccion {
    
    private static final long serialVersionUID = 1L;
    
    protected long id;
    protected String calle;
    protected String codPostal;
    protected String localidad;
    protected String pais;
    protected String telf1;
    protected String telf2;
    protected String email1;
    protected String email2;
    protected String fax;
    protected Cliente cliente;

    public Direccion() {
        super();
    }
    
    @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="direccion_seq")
    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }
    
    public String getCalle() {
        return calle;
    }

    public void setCalle(String direccion) {
        this.calle = direccion;
    }

    public String getCodPostal() {
        return codPostal;
    }

    public void setCodPostal(String codPostal) {
        this.codPostal = codPostal;
    }

    public String getLocalidad() {
        return localidad;
    }

    public void setLocalidad(String localidad) {
        this.localidad = localidad;
    }

    public String getPais() {
        return pais;
    }

    public void setPais(String pais) {
        this.pais = pais;
    }

    public String getTelf1() {
        return telf1;
    }

    public void setTelf1(String telf1) {
        this.telf1 = telf1;
    }

    public String getTelf2() {
        return telf2;
    }

    public void setTelf2(String telf2) {
        this.telf2 = telf2;
    }

    public String getEmail1() {
        return email1;
    }

    public void setEmail1(String email1) {
        this.email1 = email1;
    }

    public String getEmail2() {
        return email2;
    }

    public void setEmail2(String email2) {
        this.email2 = email2;
    }

    public String getFax() {
        return fax;
    }

    public void setFax(String fax) {
        this.fax = fax;
    }    
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "cliente_id")
    public Cliente getCliente() {
        return cliente;
    }
    public void setCliente(Cliente cliente) {
        this.cliente = cliente;
    }
}
Como podemos observar tenemos una relación del tipo Many To One que hemos mapeado empleando Hibernate y hemos empleado también la etiqueta XMLRootElement como hemos marcado en negrita. Una vez que hemos realizado este paso, tenemos que crearnos una clase auxiliar que emplearemos para el marshalling. La vamos a llamar DireccionResponse y tendrá el siguiente contenido:
import java.util.List;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class DireccionResponse {

    private List<Direccion> direcciones;
   
    public void setList(List<Direccion> direcciones){
        this.direcciones = direcciones;
    }
   
    public List<Direccion> getList(){
        return direcciones;
    }
   
    public void add(Direccion direccion) {
        direcciones.add(direccion);
    }
}
Como podemos observar, esta clase solamente tiene un atributo con una lista de direcciones. Esta clase es necesario emplearla porque al Marshal no podemos pasarle una lista de objetos sino que tenemos que pasarle solamente un único objeto. Por lo tanto le pasaremos un objeto con una lista en su interior. 
Ahora por último, para realizar el marshaling necesitamos el siguiente código:
try {
           
 Criteria crit = session.createCriteria(Direccion.class);
           
 Iterator it = crit.list().iterator();
 List<Direccion> direccionesList = new ArrayList<Direccion>();
           
 while (it.hasNext()){
    direccionesList.add((Direccion) it.next());
 }
           
 DireccionResponse dr = new DireccionResponse();
 dr.setList(direccionesList);
           
 File file = new File("salidaDirecciones.xml");

 JAXBContext jaxbContext = JAXBContext.newInstance(DireccionResponse.class);
  Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
   
  jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
  jaxbMarshaller.marshal(dr, file);
}
            
 catch (JAXBException e) {
  e.printStackTrace();
 }
Lo primero que hago es mediante un criteria me traigo todas las direcciones y una vez que tengo una lista con todas las direcciones las paso a un objeto del tipo DireccionesResponse mediante dr.setList(direccionesList);.Entonces es este objeto el que le paso al Marshal para realizar el XML junto con el fichero donde quiero pintar la salida
Y con esto obtendremos el siguiente resultado, donde podemos ver como estamos creando un XML con todas las direcciones donde también podemos ver el cliente asociado a cada dirección. El resultado se obtiene en un fichero llamado salidaDirecciones.xml y es la siguiente:


No hay comentarios :

Publicar un comentario