Статьи

Схема XML в Java — Генерация XmlAdapters

В предыдущих статьях я продемонстрировал, насколько мощным может быть XmlAdapter JAXB при запуске из объектов домена. В этом примере я продемонстрирую, как использовать XmlAdapter при создании объектной модели из схемы XML. Этот пост был вдохновлен ответом на вопрос о переполнении стека (не стесняйтесь голосовать).

XMLSchema (format.xsd)

Ниже приведена схема XML, которая будет использоваться в этом примере. Интересная часть — это тип с именем
NumberCodeValueType
. У этого типа есть определенный образец, требующий, чтобы это было семизначным числом. Это число может иметь начальные нули, которые не будут упорядочены преобразованием чисел по умолчанию в JAXB.

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
 
    <xs:element name="root">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="number" type="NumberCodeValueType" />
            </xs:sequence>
        </xs:complexType>
    </xs:element>
 
    <xs:simpleType name="NumberCodeValueType">
        <xs:restriction base="xs:int">
            <xs:pattern value="[0-7]{7}" />
        </xs:restriction>
    </xs:simpleType>
 
</xs:schema>
NumberFormatter

Поскольку алгоритм JAXB по умолчанию для числового алгоритма String не будет соответствовать требованиям нашей схемы, нам нужно написать собственный форматтер. Мы должны предоставить два статических метода, один из которых охватывает наш тип в желаемом формате XML, а другой — конвертирует из формата XML.

package blog.xmladapter.bindings;
 
public class NumberFormatter {
 
    public static String printInt(Integer value) {
        String result = String.valueOf(value);
        for(int x=0, length = 7 - result.length(); x<length; x++) {
            result = "0" + result;
        }
        return result;
    }
 
    public static Integer parseInt(String value) {
        return Integer.valueOf(value);
    }
 
}
bindings.xml


Мы будем использовать файл привязок JAXB для ссылки на форматировщик:

<jxb:bindings xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:jxb="http://java.sun.com/xml/ns/jaxb" version="2.1">
    <jxb:bindings schemaLocation="format.xsd">
        <jxb:bindings node="//xs:element[@name='number']">
            <jxb:property>
                <jxb:baseType>
                    <jxb:javaType name="java.lang.Integer"
                        parseMethod="blog.xmladapter.bindings.NumberFormatter.parseInt"
                        printMethod="blog.xmladapter.bindings.NumberFormatter.printInt" />
                </jxb:baseType>
            </jxb:property>
        </jxb:bindings>
    </jxb:bindings>
</jxb:bindings>
XJC Call


Файл привязок упоминается в вызове XJC как:

xjc -d out -p blog.xmladapter.bindings -b bindings.xml format.xsd
Adapter1


Это приведет к созданию
XmlAdapter , который использует средство форматирования:

package blog.xmladapter.bindings;
 
import javax.xml.bind.annotation.adapters.XmlAdapter;
 
public class Adapter1 extends XmlAdapter<String, Integer> {
 
    public Integer unmarshal(String value) {
        return (blog.xmladapter.bindings.NumberFormatter.parseInt(value));
    }
 
    public String marshal(Integer value) {
        return (blog.xmladapter.bindings.NumberFormatter.printInt(value));
    }
 
}
корень

XMLAdapter будет ссылаться из объекта домена с помощью
@XmlJavaTypeAdapter аннотации:

package blog.xmladapter.bindings;
 
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "number"
})
@XmlRootElement(name = "root")
public class Root {
 
    @XmlElement(required = true, type = String.class)
    @XmlJavaTypeAdapter(Adapter1 .class)
    protected Integer number;
 
    public Integer getNumber() {
        return number;
    }
 
    public void setNumber(Integer value) {
        this.number = value;
    }
 
}
демонстрация


Теперь, если мы запустим следующий демонстрационный код:

package blog.xmladapter.bindings;
 
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
 
public class Demo {
 
    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Root.class);
 
        Root root = new Root();
        root.setNumber(4);
 
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(root, System.out);
    }
}