Buscar en el Blog

Mostrando entradas con la etiqueta Java Architecture for XML Binding. Mostrar todas las entradas
Mostrando entradas con la etiqueta Java Architecture for XML Binding. Mostrar todas las entradas

viernes, 10 de junio de 2011

Cómo ordenar elementos XML usando JAXB

En ésta publicación explicaré cómo ordenar los elementos XML cuando se usa JAXB, para lo que trabajaré con la versión 2.2.1.

Supongamos que tenemos el siguiente objeto de transferencia de datos (DTO), CustomerDTO:

package com.blogspot.ingmmurillo.jaxb;

import com.tandicorp.tandiesb.jaxb.XMLOutputStream;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.IOException;
import java.io.Serializable;
import java.util.Date;

@XmlRootElement
public class CustomerDTO implements Serializable {

    private String identification;
    private String internalIdentifier;
    private String firstName;
    private String lastName;
    private Date birthday;

    public String getIdentification() {
        return identification;
    }

    public void setIdentification(String identification) {
        this.identification = identification;
    }

    public String getInternalIdentifier() {
        return internalIdentifier;
    }

    public void setInternalIdentifier(String internalIdentifier) {
        this.internalIdentifier = internalIdentifier;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

   

    @Override
    public String toString() {
        XMLOutputStream xmlOutput = new XMLOutputStream();
        JAXBContext contextObj = null;
        Marshaller marshallerObj = null;
        try {
            contextObj = JAXBContext.newInstance(this.getClass());
            marshallerObj = contextObj.createMarshaller();
            marshallerObj.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshallerObj.marshal(this, xmlOutput);
            xmlOutput.flush();
            xmlOutput.close();
        } catch (JAXBException e) {
            e.printStackTrace();
            return e.getMessage();
        } catch (IOException e) {
            e.printStackTrace();
            return e.getMessage();
        } finally {
            if (contextObj != null) {
                contextObj = null;
            }
            if (marshallerObj != null) {
                marshallerObj = null;
            }
        }

        return xmlOutput.toString();
    }
}

Cómo se puede observar se colocó la anotación @XmlRootElement y se sobrescribió el método toString(). Sí se crea una instancia del DTO y se lo imprime en consola se obtendrá lo siguiente:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customerDTO>
    <birthday>1983-07-13T13:23:27.436-05:00</birthday>
    <firstName>Mauricio</firstName>
    <identification>1845122451</identification>
    <internalIdentifier>877441000001</internalIdentifier>
    <lastName>Murillo</lastName>
</customerDTO>


Por defecto el elemento raíz del documento XML es el mismo nombre de la clase con la primera letra minúscula (customerDTO) y los elementos XML se ordenan en orden alfabético: (birthday, firstName, identification, internalIdentifier, lastName)

Para cambiar el nombre del elemento raíz se asigna un valor a la variable name de la anotación @XmlRootElement y para ordenar los elementos XML se usa la anotación @XmlType asignando el orden a la propiedad propOrder como un arreglo de String. Por último, se usa la anotación @XmlTransient para evitar que el atributo internalIdentifier de la clase se muestre como elemento XML, como se muestra a continuación:


package com.blogspot.ingmmurillo.jaxb;

import com.tandicorp.tandiesb.jaxb.XMLOutputStream;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;
import java.io.IOException;
import java.io.Serializable;
import java.util.Date;

@XmlRootElement(name = "customer")
@XmlType(propOrder = {"firstName", "lastName", "identification", "birthday"})
public class CustomerDTO implements Serializable {

    private String identification;
    private String internalIdentifier;

    //...
    
    @XmlTransient
    public String getInternalIdentifier() {
        return internalIdentifier;
    }

}

Sí se imprime en consola una instancia del objeto CustomerDTO ahora se obtendrá el siguiente resultado:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customer>
    <firstName>Mauricio</firstName>
    <lastName>Murillo</lastName>
    <identification>1845122451</identification>
    <birthday>1983-07-13T14:28:48.079-05:00</birthday>
</customer> 


Referencias

miércoles, 11 de agosto de 2010

Utilización de JAXB para mapear clases Java a representaciones XML

JAXB es una tecnología Java que permite mapear clases de Java a representaciones XML. JAXB provee dos funciones fundamentales:

  1. marshal. Consiste en presentar un objeto Java en XML. Java Object > XML
  2. unmarshal. Consiste en presentar XML en un objeto Java. XML > Java Object
La versión 2.2.1 del API de JAXB puede ser descargada desde el siguiente link: https://jaxb.dev.java.net/2.2.1/JAXB2_20100511.jar

Esta versión trabaja con anotaciones con las cuáles se indica cuál será la raíz del documento XML, los elementos y los atributos. Las principales anotaciones son:

  • @XmlRootElement
  • @XmlElement
  • @XmlAttribute
En mi publicación anterior de "cómo exponer un servicio web en Mule" en el Bean Message sobrescribí el método toString para mostrar el contenido del objeto usando tags XML. Con el uso del API de JAXB ésto ya no es necesario y es reemplazado por anotaciones, como se muestra a continuación:

package com.blogspot.ingmmurillo.axisws;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;

@XmlRootElement
public class Message implements Serializable {

    private Field[] fields;
    private String from;
    private String to;   

    @XmlAttribute
    public String getFrom() {
        return from;
    }

    public void setFrom(String from) {
        this.from = from;
    }

    @XmlAttribute
    public String getTo() {
        return to;
    }

    public void setTo(String to) {
        this.to = to;
    }

    public Field[] getFields() {
        return fields;
    }

    public void setFields(Field[] fields) {
        this.fields = fields;
    }

    @Override
    public String toString() {

        OutputStream xmlOutput = new OutputStream() {
            private StringBuilder string = new StringBuilder();

            @Override
            public void write
                    (
                            int b) throws IOException {
                this.string.append((char) b);
            }

            @Override
            public String toString
                    () {
                return this.string.toString();
            }
        };

        JAXBContext contextObj = null;
        Marshaller marshallerObj = null;
        try {
            contextObj = JAXBContext.newInstance(Message.class);
            marshallerObj = contextObj.createMarshaller();
            marshallerObj.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshallerObj.marshal(this, xmlOutput);
            xmlOutput.flush();
            xmlOutput.close();
        } catch (JAXBException e) {
            e.printStackTrace();
            return e.getMessage();
        } catch (IOException e) {
            e.printStackTrace();
            return e.getMessage();
        } finally {
            if (contextObj != null) {
                contextObj = null;
            }
            if (marshallerObj != null) {
                marshallerObj = null;
            }
        }

        return xmlOutput.toString();
    }    
}

Al realizar la invocación del servicio web la respuesta obtenida es la siguiente:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <soapenv:Body>
      <ns1:sendMessageResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://ingmmurillo.blogspot.com/webservices/axis">
         <sendMessageReturn xsi:type="xsd:string"><![CDATA[<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<message to="The World" from="My Blog">
    <fields>
        <name>FirstName</name>
        <value>Mauricio</value>
    </fields>
    <fields>
        <name>LastName</name>
        <value>Mauricio</value>
    </fields>
</message>]]></sendMessageReturn>
      </ns1:sendMessageResponse>
   </soapenv:Body>
</soapenv:Envelope>


El XML de respuesta ahora fue generado automáticamente usando JAXB. En conclusión, JAXB permite ahorrar tiempo para realizar los procesos de marshal y unmarshal. Además, JAXB permite que el mantenimiento de un bean sea menos costoso, ayudando a los desarrolladores a trabajar de forma más ágil.