Java Language
JAXB
Поиск…
Вступление
JAXB или Java Architecture for XML Binding (JAXB) - это программная среда, которая позволяет разработчикам Java сопоставлять классы Java с представлениями XML. Эта страница познакомит читателей с JAXB, используя подробные примеры о его функциях, предоставляемых главным образом для маршалинга и неархивирования объектов Java в xml-формате и наоборот.
Синтаксис
JAXB.marshall (объект, fileObjOfXML);
Object obj = JAXB.unmarshall (fileObjOfXML, className);
параметры
параметр | подробности |
---|---|
fileObjOfXML | File объект XML-файла |
имя класса | Имя класса с расширением .class |
замечания
Используя инструмент XJC, доступный в JDK, java-код для структуры xml, описанный в xml-схеме (файл .xsd
), может быть сгенерирован автоматически, см. Тему XJC .
Написание XML-файла (сортировка объекта)
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class User {
private long userID;
private String name;
// getters and setters
}
Используя аннотацию XMLRootElement
, мы можем пометить класс как корневой элемент XML-файла.
import java.io.File;
import javax.xml.bind.JAXB;
public class XMLCreator {
public static void main(String[] args) {
User user = new User();
user.setName("Jon Skeet");
user.setUserID(8884321);
try {
JAXB.marshal(user, new File("UserDetails.xml"));
} catch (Exception e) {
System.err.println("Exception occurred while writing in XML!");
} finally {
System.out.println("XML created");
}
}
}
marshal()
используется для записи содержимого объекта в файл XML. Здесь user
объект и новый объект File
передаются в качестве аргументов marshal()
.
При успешном выполнении это создает XML-файл с именем UserDetails.xml
в пути класса с содержимым ниже.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<user>
<name>Jon Skeet</name>
<userID>8884321</userID>
</user>
Чтение XML-файла (unmarshalling)
Чтобы прочитать XML-файл с именем UserDetails.xml
с приведенным ниже содержимым
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<user>
<name>Jon Skeet</name>
<userID>8884321</userID>
</user>
Нам нужен класс POJO с именем User.java
как User.java
ниже.
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class User {
private long userID;
private String name;
// getters and setters
}
Здесь мы создали переменные и имя класса в соответствии с узлами XML. Чтобы сопоставить их, мы используем аннотацию XmlRootElement
в классе.
public class XMLReader {
public static void main(String[] args) {
try {
User user = JAXB.unmarshal(new File("UserDetails.xml"), User.class);
System.out.println(user.getName()); // prints Jon Skeet
System.out.println(user.getUserID()); // prints 8884321
} catch (Exception e) {
System.err.println("Exception occurred while reading the XML!");
}
}
}
Здесь метод unmarshal()
используется для анализа XML-файла. В качестве двух аргументов требуется имя файла XML и тип класса. Затем мы можем использовать методы getter объекта для печати данных.
Использование XmlAdapter для генерации желаемого формата XML
Когда желаемый формат XML отличается от объектной модели Java, реализация XmlAdapter может использоваться для преобразования объекта модели в объект XML-формата и наоборот. В этом примере показано, как поместить значение поля в атрибут элемента с именем поля.
public class XmlAdapterExample {
@XmlAccessorType(XmlAccessType.FIELD)
public static class NodeValueElement {
@XmlAttribute(name="attrValue")
String value;
public NodeValueElement() {
}
public NodeValueElement(String value) {
super();
this.value = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
public static class ValueAsAttrXmlAdapter extends XmlAdapter<NodeValueElement, String> {
@Override
public NodeValueElement marshal(String v) throws Exception {
return new NodeValueElement(v);
}
@Override
public String unmarshal(NodeValueElement v) throws Exception {
if (v==null) return "";
return v.getValue();
}
}
@XmlRootElement(name="DataObject")
@XmlAccessorType(XmlAccessType.FIELD)
public static class DataObject {
String elementWithValue;
@XmlJavaTypeAdapter(value=ValueAsAttrXmlAdapter.class)
String elementWithAttribute;
}
public static void main(String[] args) {
DataObject data = new DataObject();
data.elementWithValue="value1";
data.elementWithAttribute ="value2";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
JAXB.marshal(data, baos);
String xmlString = new String(baos.toByteArray(), StandardCharsets.UTF_8);
System.out.println(xmlString);
}
}
Автоматическая конфигурация отображения XML / XML (@XmlAccessorType)
Аннотация @XmlAccessorType
определяет, будут ли поля / свойства автоматически сериализованы в XML. Обратите внимание, что аннотации полей и методов @XmlElement
, @XmlAttribute
или @XmlTransient
имеют приоритет над настройками по умолчанию.
public class XmlAccessTypeExample {
@XmlAccessorType(XmlAccessType.FIELD)
static class AccessorExampleField {
public String field="value1";
public String getGetter() {
return "getter";
}
public void setGetter(String value) {}
}
@XmlAccessorType(XmlAccessType.NONE)
static class AccessorExampleNone {
public String field="value1";
public String getGetter() {
return "getter";
}
public void setGetter(String value) {}
}
@XmlAccessorType(XmlAccessType.PROPERTY)
static class AccessorExampleProperty {
public String field="value1";
public String getGetter() {
return "getter";
}
public void setGetter(String value) {}
}
@XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
static class AccessorExamplePublic {
public String field="value1";
public String getGetter() {
return "getter";
}
public void setGetter(String value) {}
}
public static void main(String[] args) {
try {
System.out.println("\nField:");
JAXB.marshal(new AccessorExampleField(), System.out);
System.out.println("\nNone:");
JAXB.marshal(new AccessorExampleNone(), System.out);
System.out.println("\nProperty:");
JAXB.marshal(new AccessorExampleProperty(), System.out);
System.out.println("\nPublic:");
JAXB.marshal(new AccessorExamplePublic(), System.out);
} catch (Exception e) {
System.err.println("Exception occurred while writing in XML!");
}
}
} // outer class end
Выход
Field:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<accessorExampleField>
<field>value1</field>
</accessorExampleField>
None:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<accessorExampleNone/>
Property:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<accessorExampleProperty>
<getter>getter</getter>
</accessorExampleProperty>
Public:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<accessorExamplePublic>
<field>value1</field>
<getter>getter</getter>
</accessorExamplePublic>
Конфигурация отображения XML вручную / свойства
Аннотации @XmlElement
, @XmlAttribute
или @XmlTransient
и другие в пакете javax.xml.bind.annotation
позволяют программисту указать, какие и как помеченные поля или свойства должны быть сериализованы.
@XmlAccessorType(XmlAccessType.NONE) // we want no automatic field/property marshalling
public class ManualXmlElementsExample {
@XmlElement
private String field="field value";
@XmlAttribute
private String attribute="attr value";
@XmlAttribute(name="differentAttribute")
private String oneAttribute="other attr value";
@XmlElement(name="different name")
private String oneName="different name value";
@XmlTransient
private String transientField = "will not get serialized ever";
@XmlElement
public String getModifiedTransientValue() {
return transientField.replace(" ever", ", unless in a getter");
}
public void setModifiedTransientValue(String val) {} // empty on purpose
public static void main(String[] args) {
try {
JAXB.marshal(new ManualXmlElementsExample(), System.out);
} catch (Exception e) {
System.err.println("Exception occurred while writing in XML!");
}
}
}
Указание экземпляра XmlAdapter для (повторного) использования существующих данных
Иногда необходимо использовать конкретные экземпляры данных. Отдых нежелателен, и ссылка на static
данные будет иметь запах кода.
Можно указать XmlAdapter
экземпляр по Unmarshaller
должен использовать, что позволяет пользователю использовать XmlAdapter
ей, не равна нулю-Arg конструктор и / или передавать данные к адаптеру.
пример
Пользовательский класс
Следующий класс содержит имя и образ пользователя.
import java.awt.image.BufferedImage;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlRootElement
public class User {
private String name;
private BufferedImage image;
@XmlAttribute
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@XmlJavaTypeAdapter(value=ImageCacheAdapter.class)
@XmlAttribute
public BufferedImage getImage() {
return image;
}
public void setImage(BufferedImage image) {
this.image = image;
}
public User(String name, BufferedImage image) {
this.name = name;
this.image = image;
}
public User() {
this("", null);
}
}
адаптер
Чтобы избежать одновременного создания одного и того же изображения в памяти (а также загрузки данных снова), адаптер сохраняет изображения на карте.
Для действительного кода Java 7 замените метод getImage
на
public BufferedImage getImage(URL url) {
BufferedImage image = imageCache.get(url);
if (image == null) {
try {
image = ImageIO.read(url);
} catch (IOException ex) {
Logger.getLogger(ImageCacheAdapter.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
imageCache.put(url, image);
reverseIndex.put(image, url);
}
return image;
}
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class ImageCacheAdapter extends XmlAdapter<String, BufferedImage> {
private final Map<URL, BufferedImage> imageCache = new HashMap<>();
private final Map<BufferedImage, URL> reverseIndex = new HashMap<>();
public BufferedImage getImage(URL url) {
// using a single lookup using Java 8 methods
return imageCache.computeIfAbsent(url, s -> {
try {
BufferedImage img = ImageIO.read(s);
reverseIndex.put(img, s);
return img;
} catch (IOException ex) {
Logger.getLogger(ImageCacheAdapter.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
});
}
@Override
public BufferedImage unmarshal(String v) throws Exception {
return getImage(new URL(v));
}
@Override
public String marshal(BufferedImage v) throws Exception {
return reverseIndex.get(v).toExternalForm();
}
}
Примеры XML
Следующие 2 xmls для Jon Skeet и его земля 2, которые выглядят одинаково и поэтому используют один и тот же аватар.
<?xml version="1.0" encoding="UTF-8"?>
<user name="Jon Skeet" image="https://www.gravatar.com/avatar/6d8ebb117e8d83d74ea95fbdd0f87e13?s=328&d=identicon&r=PG"/>
<?xml version="1.0" encoding="UTF-8"?>
<user name="Jon Skeet (Earth 2)" image="https://www.gravatar.com/avatar/6d8ebb117e8d83d74ea95fbdd0f87e13?s=328&d=identicon&r=PG"/>
Использование адаптера
ImageCacheAdapter adapter = new ImageCacheAdapter();
JAXBContext context = JAXBContext.newInstance(User.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
// specifiy the adapter instance to use for every
// @XmlJavaTypeAdapter(value=ImageCacheAdapter.class)
unmarshaller.setAdapter(ImageCacheAdapter.class, adapter);
User result1 = (User) unmarshaller.unmarshal(Main.class.getResource("user.xml"));
// unmarshal second xml using the same adapter instance
Unmarshaller unmarshaller2 = context.createUnmarshaller();
unmarshaller2.setAdapter(ImageCacheAdapter.class, adapter);
User result2 = (User) unmarshaller2.unmarshal(Main.class.getResource("user2.xml"));
System.out.println(result1.getName());
System.out.println(result2.getName());
// yields true, since image is reused
System.out.println(result1.getImage() == result2.getImage());
Связывание пространства имен XML с сериализуемым классом Java.
Это пример файла package-info.java
который связывает пространство имен XML с сериализуемым классом Java. Это должно быть помещено в тот же пакет, что и классы Java, которые должны быть сериализованы с использованием пространства имен.
/**
* A package containing serializable classes.
*/
@XmlSchema
(
xmlns =
{
@XmlNs(prefix = MySerializableClass.NAMESPACE_PREFIX, namespaceURI = MySerializableClass.NAMESPACE)
},
namespace = MySerializableClass.NAMESPACE,
elementFormDefault = XmlNsForm.QUALIFIED
)
package com.test.jaxb;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
Использование XmlAdapter для обрезки строки.
package com.example.xml.adapters;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class StringTrimAdapter extends XmlAdapter<String, String> {
@Override
public String unmarshal(String v) throws Exception {
if (v == null)
return null;
return v.trim();
}
@Override
public String marshal(String v) throws Exception {
if (v == null)
return null;
return v.trim();
}
}
А в package-info.java добавьте следующее объявление.
@XmlJavaTypeAdapter(value = com.example.xml.adapters.StringTrimAdapter.class, type = String.class)
package com.example.xml.jaxb.bindings;// Packge where you intend to apply trimming filter
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;