CERN – European Organization for Nuclear Research IT Department – e-Business Section ИСПОЛЬЗОВАНИЕ ТЕХНОЛОГИИ JAXB ПРИ РАЗРАБОТКЕ XML ПРИЛОЖЕНИЙ Afonin Alexey, Derek Mathieson e-Business section, IT department CERN – Geneva, Switzerland JAXB JAXB: The Java Architecture for XML Binding Спецификация принята 8 Января 2003 года http://java.sun.com/xml/downloads/jaxb.html Доступные реализации: SUN, является частью Java Web Services Developer Pack http://java.sun.com/xml/downloads/jaxb.html Apache JAXME http://ws.apache.org/jaxme/ Архитектура JAXB Пример: XML <orders-list> <order> <number>1001</number> <date>2005-01-01</date> <description>First Order</description> <amount>10</amount> </order> <order> <number>1002</number> <date>2005-01-02</date> <description>Second Order</description> <amount>20.2</amount> </order> </orders-list> Пример: XML Schema <xsd:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xsd:element name="orders-list"> <xsd:complexType> <xsd:sequence> <xsd:element ref="order" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="order"> <xsd:complexType> <xsd:sequence> <xsd:element name="number" type="xsd:long"/> <xsd:element name="date" type="xsd:date"/> <xsd:element name="description" type="xsd:string"/> <xsd:element name="amount" type="xsd:double"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema> Пример: Генерация Java классов Из командной строки: %jwsdp.home%\jaxb\bin\xjc.bat -p generated -d src simple-order.xsd Из скрипта Ant: <project basedir="." default="generate"> <taskdef name="xjc" classname="com.sun.tools.xjc.XJCTask“ classpathref="classpath“> <target name="generate"> <xjc schema="simple-order.xsd" target="src" package="generated"/> </target> </project> Пример: сгенерированные Java классы OrdersListType.java public interface OrdersListType { java.util.List getOrder(); } OrderType.java public interface OrderType { double getAmount(); void setAmount(double value); java.lang.String getDescription(); void setDescription(java.lang.String value); java.util.Calendar getDate(); void setDate(java.util.Calendar value); long getNumber(); void setNumber(long value); } Пример: работа с JAXB Чтение из XML файла JAXBContext jaxbCtx = JAXBContext.newInstance("generated"); Unmarshaller unmarshaller = jaxbCtx.createUnmarshaller(); OrdersListType orders = (OrdersListType)unmarshaller.unmarshal( new File("simple-order.xml")); List ordersList = orders.getOrder(); for (int i = 0; i < ordersList.size(); i++) { OrderType order = (OrderType)ordersList.get(i); System.out.println("Number = " + order.getNumber() + ", amount = " + order.getAmount()); } ... Пример: работа с JAXB Изменение XML файла ... ObjectFactory objectFactory = new ObjectFactory(); Order newOrder = objectFactory.createOrder(); newOrder.setNumber(2006); newOrder.setDate(Calendar.getInstance()); newOrder.setDescription("New Order"); newOrder.setAmount(100); orders.getOrder().add(newOrder); Marshaller marshaller = jaxbCtx.createMarshaller(); marshaller.marshal(orders, new FileOutputStream(new File("simple-order.xml"))); Пакет Связывания Binding Framework Пакет Связывания Основные операции: маршаллинг (marshalling) демаршаллинг (unmarshalling) проверка (validation) Класс javax.xml.bind.JAXBContext - "точка входа" в JAXB API public abstract class JAXBContext { static JAXBContext newInstance(String contextPath) static JAXBContext newInstance(String contextPath, ClassLoader contextPathCL) abstract Unmarshaller createUnmarshaller(); abstract Marshaller createMarshaller(); abstract Validator createValidator(); } Проверка XML документа JAXB предоставляет три варианта проверки XML документа: во время демаршаллинга (unmarshall-time validation) по требованию (on-demand validation) "на лету" (fail-fast validation) Validator позволяет проверять объектное представление документа public interface Validator { ValidationEventHandler getEventHandler() void setEventHandler(ValidationEventHandler handler) boolean validate(java.lang.Object subrootObject) boolean validateRoot(java.lang.Object rootObject) } Демаршаллинг Unmarshaller читает XML документ, выполняет его проверку и строит объектную модель public interface Unmarshaller { boolean isValidating() throws JAXBException; void setValidating(boolean b) throws JAXBException; ValidationEventHandler getEventHandler() throws JAXBException; void setEventHandler(ValidationEventHandler handler) throws JAXBException; Object Object Object Object Object Object } unmarshal(File file) throws JAXBException; unmarshal(InputStream is) throws JAXBException; unmarshal(URL url) throws JAXBException; unmarshal(Source source) throws JAXBException; unmarshal(Node node) throws JAXBException; unmarshal(InputSource is) throws JAXBException; Маршаллинг Marshaller сохраняет объектную модель в XML документ public interface Marshaller { ValidationEventHandler getEventHandler() throws JAXBException; void setEventHandler(ValidationEventHandler handler) throws JAXBException; void void void void void Node marshal(Object marshal(Object marshal(Object marshal(Object marshal(Object getNode(Object o, o, o, o, o, o) OutputStream os) throws JAXBException; Writer writer) throws JAXBException; Result result) throws JAXBException; Node node) throws JAXBException; ContentHandler ch) throws JAXBException; throws JAXBException; Object getProperty(String s) throws PropertyException; void setProperty(String s, Object o) throws PropertyException; String JAXB_ENCODING = "jaxb.encoding"; String JAXB_FORMATTED_OUTPUT = "jaxb.formatted.output"; } Связывание XML схемы и Java Представления Binding XML Schema to Java Classes Связывание имен: XML Java XML Имя Имя Класса Имя Метода Имя Константы MixedCaseName getMixedCaseName MIXED_CASE_NAME Answer42 getAnswer42 ANSWER_42 name-with-dashes NameWithDashes getNameWithDashes NAME_WITH_DASHES other_punct-chars OtherPunctChars getOtherPunctChars OTHER_PUNCT_CHARS mixedCaseName Answer42 Связывание составных типов данных Составной тип XML схемы Java интерфейс <xsd:complexType name="personType"> <xsd:sequence> <xsd:element name="name" type="xsd:string"/> <xsd:element name="departmentId" type="xsd:long"/> </xsd:sequence> <xsd:attribute name="id" type="xsd:long"/> </xsd:complexType> public interface PersonType { long getDepartmentId(); void setDepartmentId(long value); java.lang.String getName(); void setName(java.lang.String value); long getId(); void setId(long value); } Свойства (Properties) Вложенные компоненты XML схемы Java свойства Простое свойство (Simple Property) <xsd:element name="name" type="xsd:string"/> java.lang.String getName(); void setName(java.lang.String value); Группа свойств (Collection Property) <xsd:element name="item" type="xsd:string" maxOccurs="unbounded"/> java.util.List getItem(); Перечисление (Type Safe Enumeration) Производный атомарный тип данных с ограничением типа «перечисление» Перечисление (Type Safe Enumeration) <xsd:simpleType name="countryType"> <xsd:restriction base="xsd:NCName"> <xsd:enumeration value="FRANCE"/> <xsd:enumeration value="SWITZERLAND"/> </xsd:restriction> </xsd:simpleType> public class CountryType { private final String value; protected CountryType(String v) { value = v; } public final static CountryType FRANCE = new CountryType("FRANCE"); public final static CountryType SWITZERLAND = new generated.CountryType("SWITZERLAND"); ... } Связывание встроенных типов данных Таблица соответствия встроенных типов (Simple Built-in Types) Тип данных XML схемы Тип данных Java xsd:string java.lang.String xsd:integer java.math.BigInteger xsd:int int xsd:long long xsd:decimal java.math.BigDecimal xsd:float float xsd:double double xsd:boolean boolean xsd:byte byte xsd:dateTime java.util.Calendar xsd:anySimpleType java.lang.String Наследование Наследование XML типов через ограничение (restriction) или расширение (extension) Java наследование <xsd:complexType name="Address"> <xsd:sequence> <xsd:element name="name" type="xsd:string"/> <xsd:element name="street" type="xsd:string"/> <xsd:element name="city" type="xsd:string"/> </xsd:sequence> </xsd:complexType> <xsd:complexType name="USAddress"> <xsd:complexContent> <xsd:extension base="Address"> <xsd:sequence> <xsd:element name="state" type="xsd:string"/> <xsd:element name="zip" type="xsd:integer"/> </xsd:sequence> </xsd:extension> </xsd:complexContent> </xsd:complexType> Наследование Наследование XML типов через ограничение (restriction) или расширение (extension) Java наследование public interface Address { java.lang.String getCity(); void setCity(java.lang.String value); java.lang.String getStreet(); void setStreet(java.lang.String value); java.lang.String getName(); void setName(java.lang.String value); } public interface USAddress extends Address { java.lang.String getState(); void setState(java.lang.String value); long getZip(); void setZip(long value); } Переопределение Связывания Customizing JAXB Bindings Зачем Переопределять? Стандартное связывания (Default Binding) Переопределение связывания: создание документации (Javadoc) изменение правил именования разрешить конфликтов имен определить имена для констант перечислений определять свои типы данных для атрибутов переопределять связывание встроенных типов переопределять маршаллинг / демаршаллинг для пользовательских типов данных Встроенное и Внешнее Переопределение Встроенное переопределение – внутри XML схемы <xs:annotation> <xs:appinfo> <!-- binding declarations --> </xs:appinfo> </xs:annotation> Внешнее переопределение – отдельный файл <jxb:bindings schemaLocation = "xs:anyURI"> <jxb:bindings node = "xs:string">* <!-- binding declarations --> <jxb:bindings> </jxb:bindings> Использование Внешнего Переопределения Командная строка xjc –b <file> <schema> Скрипт Ant <xjc schema="simple-order.xsd" target="src" binding="cxml-binding.xjb" package="generated"/> Глобальные Переопределения <globalBindings> [ collectionType = "collectionType" ] [ generateIsSetMethod= "true" | "false" | "1" | "0" ] [ enableFailFastCheck = "true" | "false" | "1" | "0" ] [ underscoreBinding = "asWordSeparator" | "asCharInWord" ] [ typesafeEnumBase = "typesafeEnumBase" ] [ <javaType> ... </javaType> ]* </globalBindings> Переопределения Уровня Схемы <schemaBindings> [ <package> package </package> ] [ <nameXmlTransform> ... </nameXmlTransform> ]* </schemaBindings> <package [ name = "packageName" ] [ <javadoc> ... </javadoc> ] </package> <nameXmlTransform> [ <typeName [ suffix="suffix" ] [ prefix="prefix" ] /> ] [ <elementName [ suffix="suffix" ] [ prefix="prefix" ] /> ] </nameXmlTransform> Переопределения Типов Данных и Компонент Связывание Классов <class [ name = "className"] [ implClass= "implClass" ] > [ <javadoc> ... </javadoc> ] </class> Связывание Свойств <property[ name = "propertyName"] [ collectionType = "propertyCollectionType" ] [ generateIsSetMethod = "true" | "false" | "1" | "0" ] [ enableFailFastCheck ="true" | "false" | "1" | "0" ] [ <baseType> ... </baseType> ] [ <javadoc> ... </javadoc> ] </property> <baseType> <javaType> ... </javaType> </baseType> Переопределения Типов Данных и Компонент Преобразование типов данных Java XML <javaType name= "javaType" [ xmlType= "xmlType" ] [ parseMethod= "parseMethod" ] [ printMethod= "printMethod" ]/> Пример Настройки Связывания <jxb:bindings xmlns:jxb="http://java.sun.com/xml/ns/jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0"> <jxb:bindings schemaLocation="cxml.xsd" node="/xs:schema" > <jxb:schemaBindings> <jxb:package name="cern.edh.cxml.objects"/> <jxb:nameXmlTransform> <jxb:typeName suffix="Type"/> </jxb:nameXmlTransform> </jxb:schemaBindings> ... Пример Настройки Связывания <jxb:bindings node="/xs:schema" schemaLocation="cxml.xsd"> ... <jxb:bindings node="//xs:simpleType[@name='datetime.tz']"> <jxb:javaType name="java.util.Date" parseMethod="cern.edh.cxml.DateConverter.parseDateTz" printMethod="cern.edh.cxml.DateConverter.printDateTz"/> </jxb:bindings> <jxb:bindings node="//xs:simpleType[@name='deploymentModeValue']"> <jxb:typesafeEnumClass/> </jxb:bindings> </jxb:bindings> </jxb:bindings> Пример: Разрешение Конфликтов Имен <xs:element name="Money" type="Money"/> <xs:complexType name="Money"> <xs:simpleContent> <xs:extension base="xs:string"> <xs:attribute name="currency" type="xs:string"/> <xs:attribute name="alternateAmount" type="xs:double"/> <xs:attribute name="alternateCurrency" type="xs:string"/> </xs:extension> </xs:simpleContent> </xs:complexType> cern.edh.cxml.objects.Money cern.edh.cxml.objects.MoneyType <jxb:nameXmlTransform> <jxb:typeName suffix="Type"/> </jxb:nameXmlTransform> Пример: Преобразование Типов Данных <jxb:bindings node="//xs:simpleType[@name='datetime.tz']"> <jxb:javaType name="java.util.Date" parseMethod="cern.edh.cxml.DateConverter.parseDateTz" printMethod="cern.edh.cxml.DateConverter.printDateTz"/> </jxb:bindings> package cern.edh.cxml; public class DateConverter { public static java.util.Date parseDateTz(String lexicalDate) throws ParseException {...} public static String printDateTz(java.util.Date date) {...} } Пример: Преобразование Типов Данных <xs:simpleType name="datetime.tz"> <xs:restriction base="xs:string"/> </xs:simpleType> <xs:element name="cXML"> ... <xs:attribute name="timestamp" type="datetime.tz"/> <xs:element name="cXML"> public interface CXMLType { ... java.util.Date getTimestamp(); void setTimestamp(java.util.Date value); } <cXML timestamp="2000-08-03T08:49:09+07:00"> ... </cXML> Пример: Перечисление <jxb:bindings node="//xs:simpleType[@name='deploymentModeValue']"> <jxb:typesafeEnumClass/> </jxb:bindings> <xs:simpleType name="deploymentModeValue"> <xs:restriction base="xs:sting"> <xs:enumeration value="production"/> <xs:enumeration value="test"/> </xs:restriction> </xs:simpleType> public class DeploymentModeValue { public final static DeploymentModeValue PRODUCTION = new DeploymentModeValue(_PRODUCTION); public final static DeploymentModeValue TEST = new DeploymentModeValue(_TEST); ... } JAXB vs. JAXP JAXB следует использовать когда нужно: Создавать объектные представления данных XML Обрабатывать только верные данные Преобразовывать данные к различным типам JAXP следует использовать когда нужно: Обрабатывать документы, построенные на различных DTD Обрабатывать документы, которые не обязательно являются правильными Применять XSLT преобразования Обрабатывать лишь отдельные части XML документа Использование JAXB Система Электронного Документооборота (EDH) Приложение электронной коммерции B2B: стандарт cXML ~ 100 интерфейсов объектной модели ~ 100 классов реализации Спасибо за внимание! XML элемент XML элемент Java интерфейс элемента Тип элемента объявлен составным (Complex type definition): <xsd:complexType name="personType"> ... <!-– вложенные элементы --> </xsd:complexType> <xsd:element name="person" type="personType"/> public interface PersonType { ... <!– свойства для вложенных элементов --> } public interface Person extends javax.xml.bind.Element, PersonType { } XML элемент XML элемент Java интерфейс элемента Тип элемента объявлен простым (Simple type definition): <xsd:element name="name" type="xsd:string"/> public interface Name extends javax.xml.bind.Element { java.lang.String getValue(); void setValue(java.lang.String value); } Уровни Действия Переопределения Компонент Тип Данных Схема Глобальные Переопределения Каждый следующий уровень по отношению к предыдущему: наследует переопределяет