Mappatura Java-XML semplificata con JAXB 2.0

L'architettura Java per l'associazione XML fornisce un modo potente e pratico di lavorare con il contenuto XML dalle applicazioni Java. Il JAXB 2.0 appena rilasciato offre molte nuove funzionalità, incluso il supporto completo di tutte le funzionalità XML Schema, un numero significativamente inferiore di classi generate, classi generate più facili da manipolare e un meccanismo di convalida più flessibile.

Per capire come elaborare i documenti XML in Java con JAXB 2.0, dobbiamo esaminare i due componenti principali di JAXB:

  • Il compilatore di binding, che associa un dato schema XML a un set di classi Java generate
  • Il framework di runtime vincolante, che fornisce funzionalità di unmarshalling, marshalling e convalida

Il compilatore di binding JAXB (o xbj) consente di generare classi Java da un dato schema XML. Il compilatore di binding JAXB trasforma uno schema XML in una raccolta di classi Java che corrispondono alla struttura descritta nello schema XML. Queste classi sono annotate con speciali annotazioni JAXB, che forniscono al framework di runtime le mappature necessarie per elaborare i documenti XML corrispondenti.

Il binding runtime framework fornisce un meccanismo efficiente e di facile utilizzo per l'unmarshalling (o la lettura) e il marshalling (o la scrittura) di documenti XML. Consente di trasformare un documento XML in una gerarchia di oggetti Java (unmarshalling) o, inversamente, di trasformare una gerarchia di oggetti Java in formato XML (marshalling). Il termine schieramento si riferisce tradizionalmente alla disposizione delle truppe in un modo appropriato. In rete, si riferisce al posizionamento degli elementi di dati in un buffer prima di inviarli su un canale di comunicazione.

Combinati, questi due componenti producono una tecnologia che consente agli sviluppatori Java di manipolare facilmente i dati XML sotto forma di oggetti Java, senza dover conoscere i dettagli nitidi della Simple API for XML Processing (SAX) o del Document Object Model (DOM) , o anche le sottigliezze di XML Schema.

Prerequisiti JAXB

Per iniziare con JAXB 2.0 è necessario:

  • Java Platform, Standard Edition 5: JAXB 2.0 fa molto affidamento sulle funzionalità di Java SE 5, come annotazioni e generici
  • Un'implementazione di JAXB 2.0

Questo articolo è stato scritto utilizzando la release candidate per l'implementazione di riferimento JAXB di GlassFish.

Genera classi Java utilizzando il compilatore JAXB

Il compilatore JAXB associa uno schema XML a una serie di classi Java. Uno schema XML è un documento XML che descrive, in modo molto preciso, gli elementi e gli attributi autorizzati in un certo tipo di documento XML. In questo esempio, utilizziamo un sistema di prenotazione del corso di formazione che può accettare ordini in formato XML. Un ordine tipico è simile a questo:

    10 Coyote Avenue, Arizona, USA     

Lo schema XML corrispondente descrive come viene prenotato il corso di formazione e contiene i dettagli del corso prenotato, gli studenti iscritti, l'azienda che effettua la prenotazione e così via. Una descrizione dello schema XML è estremamente rigorosa e può includere dettagli come il numero di elementi consentiti in un elenco di oggetti (cardinalità), attributi facoltativi e obbligatori e altro ancora. Lo schema per le prenotazioni del corso di formazione (chiamato course-booking.xsd) è mostrato qui:

Lo strumento della riga di comando xjcesegue il compilatore JAXB. Per eseguire il compilatore JAXB sul nostro schema, eseguiamo il seguente comando:

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

Questo genererà una serie di classi Java annotate con annotazioni JAXB 2.0. Alcune delle opzioni più utili sono descritte qui:

  • -d : Posiziona i file generati in questa directory.
  • -p : Posiziona i file generati in questo pacchetto.
  • -nv: Non eseguire una convalida rigorosa dello schema di input.
  • -httpproxy : Usalo se sei dietro un proxy. Accetta il formato [user[:password]@]proxyHost[:proxyPort].
  • -classpath : Specificare il percorso di classe, se necessario.
  • -readOnly: Genera file di codice sorgente di sola lettura, se il tuo sistema operativo lo supporta.

Esiste anche un'attività equivalente ant, che rende abbastanza facile l'integrazione in un processo di compilazione basato su Ant o Maven.

L'elenco delle classi generate è mostrato qui:

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

Gli utenti delle versioni precedenti di JAXB potrebbero notare che questo è un insieme semplice di classi Java annotate e completamente documentate, piuttosto che l'insieme più ingombrante di interfacce e implementazioni delle versioni precedenti. Pertanto, abbiamo classi generate meno e codice più leggero ed elegante. E, come vedrai nella prossima sezione, manipolare queste classi è facile.

Unmarshalling di un documento XML

Unmarshalling è il processo di conversione di un documento XML in un insieme corrispondente di oggetti Java. Unmarshalling in JAXB 2.0 è facile. Innanzitutto, crei un JAXBContextoggetto contesto. L'oggetto contesto è il punto di partenza per operazioni di marshalling, unmarshalling e convalida. Qui si specifica il pacchetto Java contenente le classi mappate JAXB:

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

Per annullare l'unmarshalling di un documento XML, creane uno Unmarshallerdal contesto, come mostrato qui:

 Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();

I unmarshallerdati di processo possono XML da una vasta gamma di fonti di dati: file, flussi di input, URL, oggetti DOM, SAX parser, e altro ancora. Qui forniamo un semplice Fileoggetto che punta al nostro documento XML. Il unmarshallerrestituisce un tipizzato JAXBElement, da cui possiamo ottenere il nostro oggetto deserializzati utilizzando il getValue()metodo:

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

CourseBooking booking = bookingElement.getValue();

Validazione del documento

La convalida del documento è il processo per garantire che il documento XML corrisponda alla definizione fornita nello schema XML corrispondente. È un aspetto importante di qualsiasi progetto che coinvolge scambi XML, soprattutto se l'XML proviene da altri sistemi. La convalida dei documenti in JAXB 2.0 è più semplice e flessibile rispetto alle versioni precedenti. Puoi semplicemente allegare un ValidatonEventHandlera unmarshallerprima di decomprimere il documento XML, come mostrato qui:

 unmarshaller.setEventHandler(new BookingValidationEventHandler());

Un gestore di eventi di convalida implementa l' ValidationEventHandlerinterfaccia e il handleEvent()metodo, come mostrato di seguito:

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

Successivamente, crei un JAXBElementoggetto che incapsula il tuo oggetto di dominio. Il tipo JAXBElementcorrisponde all'elemento radice complexTypedel documento XML. Quindi usa la ObjectFactoryclasse generata come segue:

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

In questo esempio, impostiamo una proprietà in modo che l'output venga formattato per uso umano e quindi scriviamo nell'output standard:

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

Un esempio di codice completo è mostrato qui:

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

L'esecuzione di questo codice genererà qualcosa del genere: