В этой статье поговорим о JAXB ( Java Architecture for XML Binding ), это стандарт который помогает нам быстро
преобразовывать xml файлы в объекты POJO, этот процесс называют демаршалингом
( Unmarshalling ), и делать обратное преобразование из
объектов POJO в xml файлы, его еще называют маршалингом ( Marshalling ). Во
всех преобразованиях, нам помогают аннотации jaxb, которые мы применяем к объекту POJO, в
принципе мы можем, без каких либо проблем использовать вместе аннотации JPA и JAXB, что позволяет нам, например из баз данных
получать на прямую xml данные и наоборот, представьте какая мощь
заключена в этой библиотеке. И так, эта
библиотека уже включена в поставку вашего jdk, с 6 версии, давайте узнаем версию нашей
библиотеки, выполним команду:
C:\Users\kamaz1>xjc
-version
xjc 2.2.8-b130911.1802
Для начала
напишем простой пример, маршалинга и демаршалинга и потом будем постепенно
усложнять наш пример и учится более сложным вещам. И так для того что бы мы
смогли делать преобразования, нам понадобиться объект POJO, пометим
его аннотациями:
package
com.vit.fly;
import
javax.xml.bind.annotation.XmlAttribute;
import
javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import
java.io.Serializable;
import
java.util.Date;
@XmlRootElement()//корневой тег
xml документа
public class
Vit1 implements Serializable{
public String name;
public Date date;
public String getName() {
return name;
}
@XmlElement()//вложенный тег в корневой тег xml
документа
public void setName(String name) {
this.name = name;
}
public Date getDate() {
return date;
}
@XmlAttribute//атрибут корневого тега
public void setDate(Date date) {
this.date = date;
}
@Override
public String toString() {
return new String("[ name=
"+name+", date= "+date.toString()+" ]");
}
}
Напишем с начала
преобразование из объекта в xml документ:
package
com.vit.fly;
import
javax.xml.bind.JAXBContext;
import
javax.xml.bind.JAXBException;
import
javax.xml.bind.Marshaller;
import
java.io.File;
import
java.util.Date;
public class
MainVit1 {
static public void main(String args[]){
Vit1 vit1 = new Vit1();
vit1.setName("Vit");
vit1.setDate( new Date());
try {
File file = new
File("vit.xml");
JAXBContext jaxbContext =
JAXBContext.newInstance(Vit1.class);//создаем контекст jaxb
Marshaller marshaller =
jaxbContext.createMarshaller();//получаем marshaller
marshaller.marshal(vit1,file);//создаем xml файл
marshaller.marshal(vit1,System.out);//выводим xml преобразование
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
Получили такой xml файл:
<?xml
version="1.0" encoding="UTF-8"
standalone="yes"?>
<vit1 date="2015-12-25T21:13:27.465+03:00">
<name>Vit</name>
</vit1>
Напишем
обратное преобразование из нашего xml документа в pojo объект:
package
com.vit.fly;
import
javax.xml.bind.JAXBContext;
import
javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import
java.io.File;
public class
MainVit2 {
static public void main(String args[]){
try {
File file = new
File("vit.xml");
JAXBContext jaxbContext =
JAXBContext.newInstance(Vit1.class);//создаем контекст jaxb
Unmarshaller unmarshaller =
jaxbContext.createUnmarshaller();//получаем unmarshaller
Vit1 vit1 =
(Vit1)unmarshaller.unmarshal(file);//получаем pojo
объект из xml файла
System.out.println(vit1);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
Получили такой
вывод:
[ name= Vit,
date= Fri Dec 25 21:13:27 GMT+03:00 2015 ]
Добавим поле
lastName и установим ему значение, затем попробуем сформировать xml файл:
@XmlRootElement()
public class
Vit1 implements Serializable{
private String name;
public String lastName;
private Date date;
…
public class
MainVit1 {
static public void main(String args[]){
Vit1 vit1 = new Vit1();
vit1.lastName = "Lopanov";
vit1.setName("Vit");
vit1.setDate( new Date());
try {
File file = new
File("vit.xml");
JAXBContext jaxbContext =
JAXBContext.newInstance(Vit1.class);//создаем контекст jaxb
Marshaller marshaller =
jaxbContext.createMarshaller();//получаем marshaller
marshaller.marshal(vit1,file);//создаем xml файл
marshaller.marshal(vit1,System.out);//выводим xml преобразование
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
На выходе
получили такой файл:
<?xml
version="1.0" encoding="UTF-8"
standalone="yes"?>
<vit1
date="2015-12-27T18:53:08.767+03:00">
<lastName>Lopanov</lastName>
<name>Vit</name>
</vit1>
Этот пример показывает,
что по умолчанию jaxb преобразует все public поля и методы доступа в теги, это поведение
можно переопределить с помощью аннотации @XmlAccessorType(). Значение
XmlAccessType.PUBLIC_MEMBER – применимо по умолчанию, XmlAccessType.FIELD – преобразует
все имеющиеся поля вне зависимости от методов доступа поля класса, XmlAccessType.PROPERTY – преобразует, все поля класса, у кого есть методы доступа set и get (сеттеры и геттеры). Если нужно не включать ни какие поля класса в
преобразования, выберите XmlAccessType.NONE,
применяется обычно к зависимым объектам, которые не нужно преобразовывать в xml теги. Предыдущий пример можно переписать
так, добавив аннотацию @XmlAccessorType():
@XmlRootElement()
@XmlAccessorType(value
= XmlAccessType.PUBLIC_MEMBER)//значение
по умолчанию
public class
Vit1 implements Serializable{
private String name;
public String lastName;
….
Если вы
примените аннотацию к любому полю @XmlTransient, то такое поле будет исключено
из преобразования в xml.
@XmlRootElement()
public class
Vit1 implements Serializable{
private String name;
@XmlTransient //
поле не отобразится в xml
public String lastName;
….
Вывод на выходе:
<?xml
version="1.0" encoding="UTF-8"
standalone="yes"?>
<vit1 date="2015-12-27T18:53:08.767+03:00">
<name>Vit</name>
</vit1>
По умолчанию
теги в xml файл выгружаются без
сортировки по алфавиту, в какой
последовательности вы опишите поля в классе, так они и выведутся в файл, если у
вас много тегов, примените аннотацию @XmlAccessorOrder и укажите в нем параметр
XmlAccessOrder.ALPHABETICAL, тогда ваши теги будут отсортированы в алфавитном
порядке. Для примера уберем на время аннотацию @XmlAttribute для наглядности:
@XmlRootElement()
@XmlAccessorOrder(value = XmlAccessOrder.ALPHABETICAL)
public class
Vit1 implements Serializable{
private String name;
public String lastName;
private Date date;
…
Даст нам такой вывод:
<?xml
version="1.0" encoding="UTF-8"
standalone="yes"?>
<vit1>
<date>2016-03-21+03:00</date>
<lastName>Lopanov</lastName>
<name>Vit</name>
</vit1>
Вернемся к
аннотации @XmlRootElement, параметр name задает имя тега, параметр namespace указывает
пространство имен, например:
@XmlRootElement(name
= "VitRoot",namespace = "Hello/Vit")
public class Vit1 implements {
private String name;
public String lastName;
private Date date;
….
}
преобразуется
в такой xml код:
<?xml
version="1.0" encoding="UTF-8"
standalone="yes"?>
<ns2:VitRoot xmlns:ns2="Hello/Vit">
<name>Vit</name>
<lastName>Lopanov</lastName>
<date>2016-03-21+03:00</date>
</ns2:VitRoot>
Перейдем к
рассмотрению аннотации @XmlElement(), как она работает, как преобразует java типы данных в xml? Ему
помогает схема xml документа, как вы помните, в схеме
документа описываются типы полей, нашего xml файла. Наша аннотация @XmlElement()
непосредственно трансформируется в тег схемы <xs:element name="имя поля
класса" /> значение поля класса </xs:element>. Напишем схему нашего “pojo объекта” vit1.xsd:
<?xml version="1.0"
encoding="UTF-8"?>
<xs:schema
targetNamespace="http://com.vit"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:vi="http://com.vit"
elementFormDefault="qualified"
>
<xs:element name="VitRoot"
type="vi:Vit1"/>
<xs:complexType
name="Vit1">
<xs:sequence>
<xs:element
name="name" type="xs:string"/>
<xs:element
name="lastName" type="xs:string"/>
</xs:sequence>
<xs:attribute name="date"
type="xs:date"/>
</xs:complexType>
</xs:schema>
Преобразуем
в java классы посредством
утилиты xjc, зададим параметры –d директория, где будут создаваться наши java классы, -p java пакет, создайте каталог в текущей директории out, выполните
команду:
C:\jboss-4.2.0.GA\vit\jboss_ejb\src>xjc
-d out -p com.vit.fly vit1.xsd
parsing a
schema...
compiling a
schema...
com\vit\fly\ObjectFactory.java
com\vit\fly\Vit1.java
com\vit\fly\package-info.java
рассмотрим файл Vit1.java, посмотрим что получилось:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name
= "Vit1", propOrder = {
"name",
"lastName"})
public class
Vit1 {
@XmlElement(required = true)
protected String name;
@XmlElement(required = true)
protected String lastName;
@XmlAttribute(name = "date")
@XmlSchemaType(name = "date")
protected XMLGregorianCalendar date;
…..
убрал getter & setter полей
}
Осталось добавить только, аннотацию @XmlRootElement и у нас
готов класс к работе, таким образом, имея схему нашего xml документа, мы можем сгенерировать классы, которые будут работать с JAXB. Обратите внимание у нас появился новый тег @XmlType(name = "Vit1", propOrder = { "name", "lastName"}), где параметр name соответствует имени типа <xs:complexType name="Vit1">, а параметр propOrder показывает порядок вывода тегов в xml файле, еще один метод “сортировки тегов”. Так же с классом Vit1.java, автоматически сформировались два файла package-info.java
и ObjectFactory.java, об ObjectFactory.java я вам расскажу позже, а сейчас
давайте поговорим о файле package-info.java. И так зачем он нужен, у каждого “приличного”
xml файла должно быть пространство имен, его можно
задать четырьмя способами. Первый способ, посредством аннотации @XmlRootElement(name = "VitRoot",namespace = "Hello/Vit"), я вам его уже
показывал в одном из примеров. Второй
способ с помощью аннотации, которая применяется к пакету класса XmlSchema() и её обычно применяют к пакету в файле package-info.java, рассмотрим содержимое этого
файла:
@javax.xml.bind.annotation.XmlSchema(namespace
= "http://com.vit", elementFormDefault =
javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package
com.vit.fly.remoteejb;
в параметре namespace
задается пространство имен по умолчанию, файл package-info.java
должен находиться вместе с классом Vit1.java в одной директории. И так обратите внимание, у нас в выводе появился
атрибут xmlns, пространство имен по умолчанию для тега vit1:
<?xml
version="1.0" encoding="UTF-8"
standalone="yes"?>
<vit1
xmlns="http://com.vit">
<name>Vit</name>
<lastName>Lopanov</lastName>
<date>2016-03-22+03:00</date>
</vit1>
Третий
способ это в аннотации @XmlType() задать параметр namespace, который имеет больший приоритет, чем в
аннотации XmlSchema(), взглянем на пример:
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name
= "vit1",namespace
= "http://com.vit1",propOrder = {"name",
"date","lastName"})
public class
Vit1 {
@XmlElement(required = true)
protected String name;
@XmlElement(required = true)
protected String lastName;
//@XmlAttribute(name = "date")
@XmlSchemaType(name = "date")
protected Date date;
…
}
Посмотрим на
вывод, что изменилось с прошлого примера, какой эффект дала нам эта аннотация:
<?xml
version="1.0" encoding="UTF-8"
standalone="yes"?>
<ns2:vit1 xmlns="http://com.vit1"
xmlns:ns2="http://com.vit">
<name>Vit</name>
<date>2016-03-23+03:00</date>
<lastName>Lopanov</lastName>
</ns2:vit1>
И последняя
четвертая возможность, если у вас есть потребность, то можно задать параметр namespace на уровне аннотаций @XmlElement() и @XmlAttribute(), т. е. применить к атрибуту или к тегу конкретное пространство имен, расмотрим
пример:
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name
= "vit1",namespace = "http://com.vit1",propOrder =
{"name", "date","lastName"})
//@XmlAccessorOrder(value
= XmlAccessOrder.ALPHABETICAL)
public class
Vit1 {
@XmlElement(required = true)
protected String name;
@XmlElement(required = true,namespace =
"http://com.vit1.element")
protected String lastName;
@XmlAttribute(name = "date",namespace =
"http://com.vit1.attribute")
//@XmlSchemaType(name = "date")
protected Date date;
…
}
И вот какой
вывод xml файла мы получили:
<?xml
version="1.0" encoding="UTF-8"
standalone="yes"?>
<ns4:vit1
xmlns="http://com.vit1" xmlns:ns2="http://com.vit1.attribute" xmlns:ns3="http://com.vit1.element"
xmlns:ns4="http://com.vit" ns2:date="2016-03-23T22:14:11.698+03:00">
<name>Vit</name>
<ns3:lastName>Lopanov</ns3:lastName>
</ns4:vit1>
Нужно
расказать еще об одной вещи, это про
префикс, его можно заменить на нужный нам, делается это все спомощью аннотации XmlSchema() задается параметром
xmlns, взглянем на наш пример:
@XmlSchema(xmlns
= {@XmlNs(prefix =
"v1", namespaceURI =
"http://www.vit.com/CC")},elementFormDefault = XmlNsForm.QUALIFIED)
package
com.vit.fly.remoteejb;
и так смотрим,
что получилось в итоге:
<?xml
version="1.0" encoding="UTF-8"
standalone="yes"?>
<vit1
xmlns:v1="http://www.vit.com/vit"
date="2016-03-24T21:42:52.749+03:00">
<name>Vit</name>
<lastName>Lopanov</lastName>
</vit1>
Давайте я
вас познакомлю еще с одной интересной аннотацией @XmlValue(), её не заслуженно забывают. Она
устанавливает значение элемента, как мы знаем, у тега могут быть, или вложенные теги, которые задаются
аннотацией @XmlElement(), или только значение, которое задается аннотацией @XmlValue(). Напишем класс, используя нашу аннотацию:
@XmlRootElement(name =
"vit2")
@XmlAccessorType(XmlAccessType.FIELD)
public class
Vit2 {
@XmlValue()
protected String name;
@XmlAttribute(name = "date")
protected Date date;
…
}
Вывод этого
класса, будет таким:
<?xml
version="1.0" encoding="UTF-8"
standalone="yes"?>
<vit2
date="2016-03-28T21:36:27.046+03:00">Vit</vit2>Next
Комментариев нет:
Отправить комментарий