Java-XML картографирането става лесно с JAXB 2.0

Java Architecture за XML Binding осигурява мощен и практичен начин за работа с XML съдържание от Java приложения. Наскоро пуснатият JAXB 2.0 предлага много нови функции, включително пълна поддръжка на всички функции на XML Schema, значително по-малко генерирани класове, генерирани класове, които са по-лесни за манипулиране, и по-гъвкав механизъм за проверка.

За да разберем как да обработваме XML документи в Java с JAXB 2.0, трябва да разгледаме двата основни компонента на JAXB:

  • Компилаторът за обвързване, който обвързва дадена XML схема с набор от генерирани Java класове
  • Обвързващата рамка за изпълнение, която осигурява функции за демаркиране, марширане и валидиране

Компилаторът за обвързване JAXB (или xbj) ви позволява да генерирате Java класове от дадена XML схема. Компилаторът за обвързване JAXB преобразува XML схема в колекция от Java класове, които съответстват на структурата, описана в XML схемата. Тези класове са анотирани със специални анотации JAXB, които предоставят на средата на изпълнение с картографиранията, необходими за обработката на съответните XML документи.

Обвързващата рамка за изпълнение осигурява ефективен и лесен за използване механизъм за демаркиране (или четене) и марширане (или писане) на XML документи. Тя ви позволява да трансформирате XML документ в йерархия на Java обекти (демаркиране) или, обратно, да трансформирате йерархията на Java обекти в XML формат (маршалиране). Терминът маршалинг традиционно се отнася до разпореждане на войски по някакъв подходящ начин. При работа в мрежа се отнася за поставяне на елементи от данни в буфер, преди да ги изпратите по комуникационен канал.

Комбинирани, тези два компонента произвеждат технология, която позволява на разработчиците на Java лесно да манипулират XML данни под формата на Java обекти, без да се налага да знаят подробностите на Simple API за XML обработка (SAX) или обектния модел на документа (DOM) , или дори тънкостите на XML Schema.

Предпоставки за JAXB

За да започнете с JAXB 2.0, трябва:

  • Java Platform, Standard Edition 5: JAXB 2.0 разчита силно на функции на Java SE 5, като анотации и генерични продукти
  • Прилагане на JAXB 2.0

Тази статия е написана с помощта на кандидата за освобождаване на еталонната реализация GlassFish JAXB

Генерирайте Java класове с помощта на JAXB компилатора

Компилаторът JAXB обвързва XML схема с набор от Java класове. XML схема е XML документ, който много точно описва елементите и атрибутите, разрешени в определен тип XML документ. В този пример използваме система за резервиране на курсове за обучение, която може да приема поръчки в XML формат. Типична поръчка изглежда така:

    10 Coyote Avenue, Arizona, USA     

Съответната XML схема описва как е резервиран курсът за обучение и съдържа подробности за резервирания курс, записаните студенти, компанията, която прави резервацията и т.н. Описанието на XML схема е изключително строго и може да включва подробности като броя на елементите, разрешени в списък с обекти (мощност), незадължителни и задължителни атрибути и др. Схемата за резервации на учебни курсове (наречена course-booking.xsd) е показана тук:

Инструментът за команден ред xjcизпълнява компилатора JAXB. За да стартираме компилатора JAXB срещу нашата схема, изпълняваме следната команда:

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

Това ще генерира набор от Java класове, анотирани с анотации JAXB 2.0. Някои от по-полезните опции са описани тук:

  • -d : Поставете генерираните файлове в тази директория.
  • -p : Поставете генерираните файлове в този пакет.
  • -nv: Не извършвайте строго валидиране на входната схема.
  • -httpproxy : Използвайте това, ако сте зад прокси. Взема формата [user[:password]@]proxyHost[:proxyPort].
  • -classpath : Посочете пътя на класа, ако е необходимо.
  • -readOnly: Генерира само файлове за изходен код, ако вашата операционна система поддържа това.

Съществува и еквивалентна antзадача, която улеснява интегрирането в процес на изграждане, базиран на Ant или Maven.

Списъкът с генерирани класове е показан тук:

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

Потребителите на предишни версии на JAXB може да забележат, че това е хлъзгав набор от коментирани и напълно документирани Java класове, а не по-тромавия набор от интерфейси и реализации на предишни версии. По този начин имаме по-малко генерирани класове и по-лек и по-елегантен код. И както ще видите в следващия раздел, манипулирането на тези класове е лесно.

Демаркиране на XML документ

Демаркирането е процесът на преобразуване на XML документ в съответния набор от Java обекти. Демаркирането в JAXB 2.0 е лесно. Първо, създавате JAXBContextконтекстен обект. Контекстният обект е началната точка за операции за марширане, демаркиране и валидиране. Тук посочвате пакета Java, съдържащ вашите JAXB-картографирани класове:

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

За да демаркирате XML документ, вие създавате Unmarshallerот контекста, както е показано тук:

 Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();

На unmarshallerданни може да обработва XML от голямо разнообразие от източници на данни: файлове, входни потоци, URL-DOM обекти, SAX парсъри и др. Тук предоставяме прост Fileобект, сочещ към нашия XML документ. Най unmarshallerвръща от напечатан JAXBElement, от които можем да се получи нашата unmarshalled обект с помощта на getValue()метода:

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

CourseBooking booking = bookingElement.getValue();

Валидиране на документи

Проверката на документа е процесът, който гарантира, че вашият XML документ съответства на дефиницията, дадена в съответната XML схема. Това е важен аспект на всеки проект, включващ XML обмен, особено ако XML идва от други системи. Валидирането на документи в JAXB 2.0 е по-лесно и по-гъвкаво, отколкото в предишните версии. Можете просто да прикачите a ValidatonEventHandlerкъм unmarshallerпреди демаркирането на XML документа, както е показано тук:

 unmarshaller.setEventHandler(new BookingValidationEventHandler());

Манипулатор на събитие за проверка реализира ValidationEventHandlerинтерфейса и handleEvent()метода, както е показано тук:

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

След това създавате JAXBElementобект, който капсулира вашия домейн обект. Въведеното JAXBElementотговаря на основния елемент complexTypeна вашия XML документ. След това използвайте генерирания ObjectFactoryклас, както следва:

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

В този пример задаваме свойство, така че изходът да бъде форматиран за човешка употреба и след това да запишем в стандартен изход:

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

Пълна извадка от код е показана тук:

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

Изпълнението на този код ще генерира нещо подобно: