Java y XML con JAXB2 (II)

08:14PM dic 06, 2007 en categoria Java por Enrique Rodriguez Lasterra

Etiquetas:


Hemos visto en el post anterior que con un schema sencillo rápidamente podemos generar nuestras clases Java para poder leer y escribir XMLs. Pero como todo en la informática, lo sencillo se convierte en complejo, dependiendo de nuestro escenario. 

Con JAXB2 podemos realizar operaciones de maquillaje en el compilador de esquemas, XJC. Vamos a ver como podemos realizar estas operaciones y como nos van a ayudar en algunas situaciones relativamente habituales.

Modo de configuración Inline y External 

Existes dos formas de realizar estas configuraciones:

  • Modo Inline: Introduciendo elementos del Schema de JAXB dentro del Schema que queremos compilar. Hay que tener en cuenta que en la mayoría de los casos este esquema esta mantenido por un tercero, por lo que para modificarlo debemos crear una copia de el. Esto puede suponer un riesgo en el futuro si se amplia/modifica el schema, ya que nos obligará a modificar nuestra copia.
  • Modo External: Mediante un fichero externo al Schema donde realizamos estas configuraciones.

La ventaja del modo en línea es que puede resultar más sencillo de leer. La ventaja del modo externo es que no tocamos el Schema y este se limita a su función original, validar los ficheros XML.

Configuraciones Globales

Existen varios tipos de configuraciones, todas ellos aplicables tanto en el modo en línea como en el externo. El más general es Global, y en el podemos configurar entre otras cosas como manejar las Colecciones de elementos XML (ArrayList, Set, etc.), decidir si crear o no una operación isSet para saber si ha sido rellenado el valor de un elemento o no o por ejemplo si un fixed attribute del Schema debe ser convertido a una constante Java o no. Veamoslo con un ejemplo

Basándonos en el Schema anterior vamos a realizar unos cambios:

  • La colección de elementos va a ser traducida a java.util.LinkedList en vez de ArrayList
  • Vamos a generar el metodo isSet en las clases Java

Usando el metodo inline debemos modificar el schema y añadir información que JAXB sabe interpretar. Para que esto sea posible sin que afecte a la misión principal del Schema, existe la etiqueta <xs:appinfo/>.  Esta etiqueta es similar a <xs:documentation/> pero orientada a dar información a aplicaciones informáticas en vez de al programador. Ambas etiquetas son hijas de <xs:annotation>. Dentro de <xs:appinfo> podemos usar etiquetas XML de JAXB que son las encargadas de realizar la configuración inline. Veamos como queda nuestro Schema con las configuraciones inline que necesitamos para este ejemplo:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://weblogs.javahispano.org/lasterra/jaxb2"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
jxb:version="2.0"

targetNamespace="http://weblogs.javahispano.org/lasterra/jaxb2"
elementFormDefault="qualified">
<xs:annotation>
<xs:documentation>
Modificamos el schema que JAXB genere LinkedList
y métidos isSet
</xs:documentation>
<xs:appinfo>
<jxb:globalBindings
collectionType="java.util.LinkedList"
generateIsSetMethod="false"
/>
</xs:appinfo>

</xsd:annotation>
<xs:element name="elemento-principal">
.....

Destacamos en el ejemplo la incorporación del namespace jxb al XSD. Este namespace importa el Schema de JAXB2 para que podamos usar dentro de nuestro Schema las etiquetas que JAXB2 utiliza para las configuraciones. En el ejemplo se puede ver <jxb:globalBindings> que es la encargada de realizar las configuraciones globales que hemos comentado. Para el ejemplo solo hemos usado las configuraciones collectionType y generateSetMethod, pero existen otras que se pueden utilizar. Los globalBindigs solo son aplicables bajo la etiqueta xs:schema, si intentamos realizar estas configuraciones bajo otro elemento el compilador nos dará error.

Si ejecutamos ahora la tarea de ANT de nuestro ejemplo, veremos los cambios en las clases generadas, a destacar los efectos en la lista de elementos CampoTres:

public List<Integer> getCampoTres() {
if (campoTres == null) {
campoTres = new LinkedList<Integer>();
}
return this.campoTres;
}

public boolean isSetCampoTres() {
return ((this.campoTres!= null)
&&(!this.campoTres.isEmpty()));
}

public void unsetCampoTres() {
this.campoTres = null;
}

En el método externo la diferencia es que estas configuraciones, el uso del las etiquetas jxb:*, se hacen en un fichero externo. Al ejecutar XJC debemos indicarle donde se encuentra este fichero y el resultado es exactamente igual. Este fichero de configuración es conocido como JAXB binding customization file y su extensión suele ser xjb. El fichero, como es de esperar, debe importar el Schema de JAXB2. Veamos como sería nuestro fichero xjb para realizar nuestro ejemplo

<jxb:bindings version="2.0"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<jxb:bindings>
<jxb:globalBindings
collectionType="java.util.LinkedList"
generateIsSetMethod="true"
/>

</jxb:bindings>
</jxb:bindings>

Al ejecutar la tarea de ant debemos pasar la ruta a este fichero de configuración a través del attributor binding, por tanto nuestro target ANT quedaría así

<target name="compile-schema">
<property name="jaxb2.path" value="D:\\jaxb-ri-20070917"/>
<taskdef name="xjc" classname="com.sun.tools.xjc.XJCTask">
<classpath>
<fileset dir="${jaxb2.path}/lib" includes="*.jar"/>
</classpath>
</taskdef>
<xjc schema="schema.xsd" package="org.javahispano.weblogs.lasterra.jaxb2.ejemplo"
destdir="${basedir}/src"
binding="jaxb2.jxb"/>
</target>
Hemos visto como se pueden aplicar configuraciones glabales tanto en línea como de forma externa. En los siguientes post veremos otras posibles configuraciones.
Comentarios:

Enviar un comentario:
Los comentarios han sido deshabilitados.