Mapeo Java-XML simplificado con JAXB 2.0

La arquitectura Java para enlaces XML proporciona una forma poderosa y práctica de trabajar con contenido XML desde aplicaciones Java. El JAXB 2.0 recientemente lanzado ofrece muchas características nuevas, incluido el soporte completo de todas las características del esquema XML, muchas menos clases generadas, clases generadas que son más fáciles de manipular y un mecanismo de validación más flexible.

Para comprender cómo procesar documentos XML en Java con JAXB 2.0, debemos observar los dos componentes principales de JAXB:

  • El compilador de enlace, que enlaza un esquema XML dado a un conjunto de clases Java generadas.
  • El marco de tiempo de ejecución vinculante, que proporciona funcionalidades de desagrupación, ordenación y validación

El compilador de enlace JAXB (o xbj) le permite generar clases Java a partir de un esquema XML determinado. El compilador de enlace JAXB transforma un esquema XML en una colección de clases Java que coinciden con la estructura descrita en el esquema XML. Estas clases están anotadas con anotaciones JAXB especiales, que proporcionan al marco de tiempo de ejecución las asignaciones que necesita para procesar los documentos XML correspondientes.

El marco de tiempo de ejecución vinculante proporciona un mecanismo eficiente y fácil de usar para desagrupar (o leer) y ordenar (o escribir) documentos XML. Le permite transformar un documento XML en una jerarquía de objetos Java (desordenación) o, a la inversa, transformar una jerarquía de objetos Java en formato XML (ordenación). El término movilización se refiere tradicionalmente a disponer de tropas de alguna manera adecuada. En redes, se refiere a colocar elementos de datos en un búfer antes de enviarlos por un canal de comunicación.

Combinados, estos dos componentes producen una tecnología que permite a los desarrolladores de Java manipular fácilmente datos XML en forma de objetos Java, sin tener que conocer los detalles esenciales de la API simple para procesamiento XML (SAX) o el Modelo de objetos de documento (DOM). , o incluso las sutilezas del esquema XML.

Requisitos previos de JAXB

Para comenzar con JAXB 2.0, necesita:

  • Java Platform, Standard Edition 5: JAXB 2.0 se basa en gran medida en funciones de Java SE 5, como anotaciones y genéricos
  • Una implementación de JAXB 2.0

Este artículo se escribió utilizando el candidato de lanzamiento de implementación de referencia GlassFish JAXB.

Genere clases de Java utilizando el compilador JAXB

El compilador JAXB vincula un esquema XML a un conjunto de clases Java. Un esquema XML es un documento XML que describe, con mucha precisión, los elementos y atributos autorizados en un determinado tipo de documento XML. En este ejemplo, utilizamos un sistema de reserva de cursos de formación que puede aceptar pedidos en formato XML. Un pedido típico se ve así:

    10 Coyote Avenue, Arizona, USA     

El esquema XML correspondiente describe cómo se reserva el curso de formación y contiene detalles del curso reservado, los estudiantes matriculados, la empresa que realiza la reserva, etc. La descripción de un esquema XML es extremadamente rigurosa y puede incluir detalles como el número de elementos permitidos en una lista de objetos (cardinalidad), atributos opcionales y obligatorios, y más. El esquema para las reservas del curso de formación (llamado course-booking.xsd) se muestra aquí:

La herramienta de línea de comandos xjcejecuta el compilador JAXB. Para ejecutar el compilador JAXB contra nuestro esquema, ejecutamos el siguiente comando:

 $xjc course-booking.xsd -p nz.co.equinox.training.domain.booking -d src/generated

Esto generará un conjunto de clases Java anotadas con anotaciones JAXB 2.0. Algunas de las opciones más útiles se describen aquí:

  • -d : Coloque los archivos generados en este directorio.
  • -p : Coloque los archivos generados en este paquete.
  • -nv: No realice una validación estricta del esquema de entrada.
  • -httpproxy : Use esto si está detrás de un proxy. Toma el formato [user[:password]@]proxyHost[:proxyPort].
  • -classpath : Especifique la ruta de clase, si es necesario.
  • -readOnly: Genera archivos de código fuente de solo lectura, si su sistema operativo lo admite.

También hay una anttarea equivalente , que facilita la integración en un proceso de compilación basado en Ant o Maven.

La lista de clases generadas se muestra aquí:

 CompanyType.java ContactType.java CourseBooking.java ObjectFactory.java StudentType.java

Los usuarios de versiones anteriores de JAXB pueden notar que este es un conjunto elegante de clases de Java anotadas y completamente documentadas, en lugar del conjunto más engorroso de interfaces e implementaciones de versiones anteriores. Por lo tanto, tenemos clases menos generadas y un código más ligero y elegante. Y, como verá en la siguiente sección, manipular estas clases es fácil.

Desorganizar un documento XML

Unmarshalling es el proceso de convertir un documento XML en un conjunto correspondiente de objetos Java. Desagrupar en JAXB 2.0 es fácil. Primero, crea un JAXBContextobjeto de contexto. El objeto de contexto es el punto de partida para las operaciones de ordenación, desorganización y validación. Aquí especifica el paquete Java que contiene sus clases mapeadas JAXB:

 JAXBContext jaxbContext = JAXBContext.newInstance ("nz.co.equinox.training.domain.booking");

Para deshacer un ordenamiento de un documento XML, crea un a Unmarshallerpartir del contexto, como se muestra aquí:

 Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();

Los unmarshallerdatos de proceso XML a partir de una amplia variedad de fuentes de datos: archivos, flujos de entrada, direcciones URL, objetos DOM, analizadores SAX, y más. Aquí proporcionamos un Fileobjeto simple que apunta a nuestro documento XML. El unmarshallerdevuelve un tipo JAXBElement, del cual podemos obtener nuestro objeto no ordenado usando el getValue()método:

JAXBElement bookingElement = (JAXBElement) unmarshaller.unmarshal( new File("src/test/resources/xml/booking.xml"));

CourseBooking booking = bookingElement.getValue();

Validación de documentos

La validación de documentos es el proceso de asegurar que su documento XML corresponda a la definición dada en el esquema XML correspondiente. Es un aspecto importante de cualquier proyecto que involucre intercambios XML, especialmente si el XML proviene de otros sistemas. La validación de documentos en JAXB 2.0 es más fácil y flexible que en versiones anteriores. Simplemente puede adjuntar una ValidatonEventHandlera la unmarshallerantes unmarshalling el documento XML, como se muestra aquí:

 unmarshaller.setEventHandler(new BookingValidationEventHandler());

Un controlador de eventos de validación implementa la ValidationEventHandlerinterfaz y el handleEvent()método, como se muestra aquí:

public class BookingValidationEventHandler implements ValidationEventHandler{

public boolean handleEvent(ValidationEvent ve) {

if (ve.getSeverity()==ValidationEvent.FATAL_ERROR || ve .getSeverity()==ValidationEvent.ERROR){ ValidationEventLocator locator = ve.getLocator(); //Print message from valdation event System.out.println("Invalid booking document: " + locator.getURL()); System.out.println("Error: " + ve.getMessage()); //Output line and column number System.out.println("Error at column " + locator.getColumnNumber() + ", line " + locator.getLineNumber()); } return true; } }

Here we just print details of the error, but in a real application, some less trivial treatment might be appropriate. In some cases, you may even consider that the validation error is not a show-stopper and that it will not block the processing. By returning true, you tell the unmarshaller to continue the unmarshalling process: false would terminate the process with an appropriate exception.

Marshalling a document

Marshalling involves transforming your Java classes into XML format. In JAXB 2.0, creating and manipulating these Java classes is simple. In most cases, you can just treat them like ordinary Java classes, as shown here:

 CourseBooking booking = new CourseBooking(); booking.setCourseReference("UML-101"); booking.setTotalPrice(new BigDecimal(10000)); ...

Note that you can still use the ObjectFactory class similarly to how you used it in JAXB 1.0, as shown in the following listing. However, unlike JAXB 1.0, there are no interfaces or implementation classes: all domain objects are just annotated JavaBeans components.

 ObjectFactory factory = new ObjectFactory(); CourseBooking booking = factory.createCourseBooking(); ...

Although most XML data types map directly to normal Java classes, some special treatment is needed for certain data types, such as dates. In these cases, you must use the DatatypeFactory, as shown here:

 DatatypeFactory datatypes = DatatypeFactory.newInstance(); booking.setCourseDate(datatypes.newXMLGregorianCalendarDate(2006,06,15,0));

Once your domain object is initialized, use the JAXB context to create a Marshaller object and a typed JAXBElement. Creating the marshaller is simple:

 Marshaller marshaller = jaxbContext.createMarshaller();

A continuación, crea un JAXBElementobjeto que encapsula su objeto de dominio. El tipo JAXBElementcorresponde al elemento raíz complexTypede su documento XML. Luego use la ObjectFactoryclase generada de la siguiente manera:

 JAXBElement bookingElement = (new ObjectFactory()).createBooking(booking);

En este ejemplo, establecemos una propiedad para que la salida se formatee para uso humano y luego se escriba en la salida estándar:

 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); marshaller.marshal( bookingElement, System.out );

Aquí se muestra un ejemplo de código completo:

JAXBContext jaxbContext = JAXBContext.newInstance("nz.co.equinox.training.domain.booking");

CourseBooking booking = new CourseBooking(); booking.setCourseReference("UML-101"); booking.setTotalPrice(new BigDecimal(10000)); booking.setInvoiceReference("123456"); DatatypeFactory datatypes = DatatypeFactory.newInstance(); booking.setCourseDate(datatypes.newXMLGregorianCalendarDate(2006,06,15,0)); booking.setTotalPrice(new BigDecimal(10000)); booking.setInvoiceReference("123456"); booking.getStudent().add(new StudentType()); booking.getStudent().get(0).setFirstName("John"); booking.getStudent().get(0).setSurname("Smith"); booking.setCompany(new CompanyType()); booking.getCompany().setName("Clients inc."); booking.getCompany().setContact(new ContactType()); booking.getCompany().getContact().setName("Paul"); booking.getCompany().getContact().setEmail("[email protected]"); booking.getCompany().getContact().setTelephone("12345678"); booking.getCompany().setAddress("10 client street");

// Marshal to System.out Marshaller marshaller = jaxbContext.createMarshaller(); JAXBElement bookingElement = (new ObjectFactory()).createBooking(booking); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

marshaller.marshal( bookingElement, System.out );

Ejecutar este código generará algo como esto: