Начиная с XML-схемы
В предыдущем ответе я описал, как решить ваш сценарий использования при запуске из объектов Java.Основываясь на ваших комментариях к этому ответу, этот ответ описывает, как можно сделать то же самое, когда модель генерируется из схемы XML.
Схема XML (attributeAdapter.xsd)
В этом примере мы будем использовать следующую XML-схему:
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema
elementFormDefault="qualified"
targetNamespace="http://www.example.com/adapter"
xmlns:nytd="http://www.example.com/adapter"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="root">
<xs:complexType>
<xs:attribute name="foo" type="xs:string"/>
<xs:attribute name="bar" type="xs:string"/>
</xs:complexType>
</xs:element>
</xs:schema>
StringConverter
Мы будемНужно определить класс для нашей специальной обработки String.Для этого варианта использования мы хотим, чтобы нулевое значение поля / свойства обрабатывалось как пустая строка ("") в документе XML:
package com.example.adapter;
public class StringConverter {
public static String parseString(String value) {
if("".equals(value)) {
return null;
}
return value;
}
public static String printString(String value) {
if(null == value) {
return "";
}
return value;
}
}
Binding File (attributeAdapterBinding.xml)
Нам потребуется использовать файл привязки JAXB для настройки генерации классов.Приведенный ниже файл привязки позволит нам использовать класс StringConverter, который мы определили выше:
<jaxb:bindings
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
version="2.1">
<jaxb:bindings schemaLocation="attributeAdapter.xsd">
<jaxb:bindings node="//xs:element[@name='root']/xs:complexType">
<jaxb:bindings node="xs:attribute[@name='foo']">
<jaxb:property>
<jaxb:baseType>
<jaxb:javaType name="java.lang.String"
parseMethod="com.example.adapter.StringConverter.parseString"
printMethod="com.example.adapter.StringConverter.printString"/>
</jaxb:baseType>
</jaxb:property>
</jaxb:bindings>
<jaxb:bindings node="xs:attribute[@name='bar']">
<jaxb:property>
<jaxb:baseType>
<jaxb:javaType name="java.lang.String"
parseMethod="com.example.adapter.StringConverter.parseString"
printMethod="com.example.adapter.StringConverter.printString"/>
</jaxb:baseType>
</jaxb:property>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
вызов XJC
Мы сделаем нашВызов XJC выглядит следующим образом:
xjc -d out -b attributeAdapterBinding.xml attributeAdapter.xsd
Модель домена (Root)
Поля / свойства, которые мы настроили в файле привязки, будутаннотирован @XmlJavaTypeAdapter;
package com.example.adapter;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "")
@XmlRootElement(name = "root")
public class Root {
@XmlAttribute
@XmlJavaTypeAdapter(Adapter1 .class)
protected String foo;
@XmlAttribute
@XmlJavaTypeAdapter(Adapter2 .class)
protected String bar;
public String getFoo() {
return foo;
}
public void setFoo(String value) {
this.foo = value;
}
public String getBar() {
return bar;
}
public void setBar(String value) {
this.bar = value;
}
}
XmlAdapter (Adapter1)
Сгенерированный класс XmlAdapter будет выглядеть примерно так:Обратите внимание, как он использует наш класс StringConverter:
package com.example.adapter;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class Adapter1 extends XmlAdapter<String, String> {
public String unmarshal(String value) {
return (com.example.adapter.StringConverter.parseString(value));
}
public String marshal(String value) {
return (com.example.adapter.StringConverter.printString(value));
}
}
Демонстрация
Теперь, если мы запустим следующий демонстрационный код:
package com.example.adapter;
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.setFoo(null);
root.setBar(null);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
Вывод
Получим желаемый вывод:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root xmlns="http://www.example.com/adapter" foo="" bar=""/>
UPDATE (файл альтернативной привязки)
В качестве альтернативы, если вы хотите, чтобы адаптер применялся ко всем свойствам типа xsd:string
, вы можете использовать файл привязки, который выглядит примерно так:
<jaxb:bindings
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
version="2.1">
<jaxb:globalBindings>
<jaxb:javaType
name="String"
xmlType="xs:string"
parseMethod="com.example.adapter.StringConverter.parseString"
printMethod="com.example.adapter.StringConverter.printString"/>
</jaxb:globalBindings>
</jaxb:bindings>