且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Jaxb:xs:属性null值

更新时间:2023-11-05 13:31:22

从XML架构开始

前面的答案我描述了从Java对象开始时如何解决用例。根据您对该答案的评论,这个答案描述了当从XML模式生成模型时如何完成同样的事情。

In a previous answer I described how to solve your use case when starting from Java objects. Based on your comments to that answer, this answer describes how the same thing can be done when the model is generated from an XML schema.

XML架构(attributeAdapter.xsd)

XML Schema (attributeAdapter.xsd)

对于此示例,我们将使用以下XML架构:

For this example we will use the following XML schema:

<?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

StringConverter

我们需要定义一个类来进行特殊的字符串处理。对于此用例,我们希望在XML文档中将空字段/属性值视为空字符串():

We will need to define a class to do our special String handling. For this use case we want a null field/property value to be treated as empty String ("") in the XML document:

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文件(attributeAdapterBinding.xml)

Binding File (attributeAdapterBinding.xml)

我们需要使用JAXB绑定文件来自定义类生成。下面的绑定文件将允许我们利用上面定义的StringConverter类:

We will need to use a JAXB binding file to customize the class generation. The binding file below will allow us to leverage the StringConverter class that we defined above:

<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 call

我们将按如下方式进行XJC调用:

We will make our XJC call as follows:

xjc -d out -b attributeAdapterBinding.xml attributeAdapter.xsd

域模型(根)

Domain Model (Root)

我们在绑定文件中自定义的字段/属性将使用@XmlJavaTypeAdapter进行注释;

The fields/properties that we customized in the binding file will be annotated with @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 (Adapter1)

生成的XmlAdapter类如下所示。注意它如何利用我们的StringConverter类:

The generated XmlAdapter class will look something like the following. Note how it leverages our StringConverter class:

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));
    }

}

演示

Demo

现在,如果我们运行以下演示代码:

Now if we run the following demo code:

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);
    }

}

输出

Output

我们将获得所需的输出:

We will get the desired output:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root xmlns="http://www.example.com/adapter" foo="" bar=""/>

更新(备用约束文件)

或者,如果您希望适配器应用于 xsd:string 类型的所有属性,那么您可以使用看起来像这样的绑定文件;

Alternatively, if you wanted the adapter applied to all properties of type xsd:string then you could use an binding file that looked something like;

<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>