使用XmlAdapter

时间:2016-11-21 17:21:17

标签: java xml xsd jaxb locale

问题:

根据Oracle提供的有关java.util.Locale:[Internationalization: Understanding Locale in the Java Platform]的使用的以下文档,我有以下与JAXB和Locale相关的问题。

我有一个如下所示的XML文件:

<?xml version="1.0" encoding="utf-8"?>
<dataschema>
  <delimited>
    <locale language="en" country="US" variant="SiliconValley" />
  </delimited>
</dataschema>

基于以下XML架构:

<?xml version="1.0" encoding="utf-8" ?>
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="dataschema">
        <xs:complexType>
            <xs:choice>
                <xs:element minOccurs="1" maxOccurs="1" name="delimited" type="DelimitedSchemaType"/>
                <xs:element minOccurs="1" maxOccurs="1" name="fixedwidth" type="FixedWidthSchemaType"/>
            </xs:choice>
        </xs:complexType>
    </xs:element>
    <xs:complexType name="DelimitedSchemaType">
        <xs:sequence>
            <xs:element minOccurs="1" maxOccurs="1" name="locale" type="LocaleType"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="FixedWidthSchemaType">
        <xs:sequence>
            <xs:element minOccurs="1" maxOccurs="1" name="locale" type="LocaleType"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="LocaleType">
        <xs:attribute name="language" use="required">
            <xs:simpleType>
                <xs:restriction base="xs:string">
                    <xs:pattern value="[a-z]{2,3}"/>
                </xs:restriction>
            </xs:simpleType>
        </xs:attribute>
        <xs:attribute name="country" use="required">
            <xs:simpleType>
                <xs:restriction base="xs:string">
                    <xs:pattern value="[A-Z]{2}"/>
                </xs:restriction>
            </xs:simpleType>
        </xs:attribute>
        <xs:attribute name="variant" use="optional">
            <xs:simpleType>
                <xs:restriction base="xs:string">
                    <xs:pattern value="[A-Z]{2}"/>
                </xs:restriction>
            </xs:simpleType>
        </xs:attribute>
    </xs:complexType>
</xs:schema>

现在的问题是我为LocaleType xml complexType获得了以下生成的类,它们似乎不反映生成的DelimitedDataSchema类中的实际java.util.Locale数据类型。我原以为这是java.util.Locale类型而不是类型为org.mylib.schema.LocaleType?

JAXB 2.x生成的类是:

Dataschema.java:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "delimited",
    "fixedwidth"
})
@XmlRootElement(name = "dataschema")
public class Dataschema {

    protected DelimitedDataSchema delimited;
    protected FixedWidthDataSchema fixedwidth;

    public DelimitedDataSchema getDelimited() {
        return delimited;
    }

    public void setDelimited(DelimitedDataSchema value) {
        this.delimited = value;
    }

    public FixedWidthDataSchema getFixedwidth() {
        return fixedwidth;
    }

    public void setFixedwidth(FixedWidthDataSchema value) {
        this.fixedwidth = value;
    }
}

DelimitedDataSchema.java:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "DelimitedSchemaType", propOrder = {
    "localeType"
})
public class DelimitedDataSchema {

    @XmlElement(required = true)
    protected LocaleType locale;

    public LocaleType getLocale() {
        return locale;
    }

    public void setLocale(LocaleType value) {
        this.locale = value;
    }
}

LocaleType:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "LocaleType")
public class LocaleType {

    @XmlAttribute(name = "language", required = true)
    protected String language;
    @XmlAttribute(name = "country", required = true)
    protected String country;
    @XmlAttribute(name = "variant")
    protected String variant;

    public String getLanguage() {
        return language;
    }

    public void setLanguage(String value) {
        this.language = value;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String value) {
        this.country = value;
    }

    public String getVariant() {
        return variant;
    }

    public void setVariant(String value) {
        this.variant = value;
    }
}

我勇敢地遵循Blaise Doughan关于JAXB XmlAdapters的以下博客文章中的说明:JAXB and Package Level XmlAdapters以及XmlAdapter - JAXB's Secret Weapon

所以我自己创建了一个XmlAdapter,希望生成的类(DelimitedDataSchema)包含getter中的java.util.Locale返回数据类型和setter中的java.util.Locale参数数据类型。我错误地认为。

LocaleXmlAdapter.java:

public class LocaleXmlAdapter extends XmlAdapter<org.mylib.schema.LocaleType, java.util.Locale> {
    @Override
    public java.util.Locale unmarshal(org.mylib.schema.LocaleType pSchemaLocale) throws Exception {
        if (pSchemaLocale == null) {
            throw new NullPointerException("LocaleXmlAdapter.unmarshal(...) received a NULL literal.");
        }

        java.util.Locale mLocale = null;
        String mLanguage = pSchemaLocale.getLanguage().toLowerCase();
        String mCountry = pSchemaLocale.getCountry().toUpperCase();
        String mVariant = pSchemaLocale.getVariant();

        if (mVariant == null) {
            mLocale = new java.util.Locale(mLanguage, mCountry);
        } else {
            mLocale = new java.util.Locale(mLanguage, mCountry, mVariant);
        }
        return mLocale;
    }

    @Override
    public org.mylib.schema.LocaleType marshal(java.util.Locale pJavaLocale) throws Exception {
        if (pJavaLocale == null) {
            throw new NullPointerException("LocaleXmlAdapter.marshal(...) received a NULL literal.");
        }

        org.mylib.schema.LocaleType mLocale = new org.mylib.schema.LocaleType();
        mLocale.setLanguage(pJavaLocale.getLanguage().toLowerCase());
        mLocale.setCountry(pJavaLocale.getCountry().toUpperCase());
        String mVariant = pJavaLocale.getVariant();
        if (mVariant != null) {
            mLocale.setVariant(mVariant);
        }

        return mLocale;
    }
}

为了让JAXB库知道它必须使用LocaleXmlAdapter,我为库提供了一个外部绑定文件,其中为Locale类定义了LocaleXmlAdapter。

外部JAXB绑定文件:

<?xml version="1.0" encoding="utf-8"?>
<jaxb:bindings jaxb:version="2.1" xmlns:xs="http://www.w3.org/2001/XMLSchema"
               xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
               schemaLocation="dataschema.xsd" node="/xs:schema">

    <jaxb:schemaBindings>
        <jaxb:package name="org.mylib.schema">
            <jaxb:javadoc>
                Package level documentation for generated package org.mylib.schema.
            </jaxb:javadoc>
        </jaxb:package>
    </jaxb:schemaBindings>

    <jaxb:bindings node="//xs:complexType[@name='LocaleType']">
        <jaxb:class name="LocaleType"/>
        <jaxb:property>
            <jaxb:baseType name="org.mylib.schema.LocaleXmlAdapter"/>
        </jaxb:property>
    </jaxb:bindings>

    <jaxb:bindings node="//xs:complexType[@name='DelimitedSchemaType']">
        <jaxb:class name="DelimitedDataSchema"/>
    </jaxb:bindings>

    <jaxb:bindings node="//xs:complexType[@name='FixedWidthSchemaType']">
        <jaxb:class name="FixedWidthDataSchema"/>
    </jaxb:bindings>
</jaxb:bindings>

现在奇怪的部分,我显然没有得到,是我希望JAXB库将org.mylib.schema.LocaleType类型转换为DelimitedDataSchema类的java.util.Locale类型,所以你会在DelimitedDataSchema类中看到以下方法签名:

  • public java.util.Locale getLocale(){}

  • public void setLocale(java.util.Locale value){}

我想要完成的是使用java.util.Locale数据类型而不是org.mylib.schema.LocaleType数据类型。如何在用户代码和JAXB生成的代码之间完成翻译?我不能自己调用​​LocaleXmlAdapter类来为我翻译语言环境类型,这必须由JAXB库完成,但我想调用:getLocale()并返回获取java.util.Locale数据类型。

我在做什么'错了'?

更新

到目前为止,我发现&lt; jaxb :baseType /&gt;不应该使用。相反,&lt; xjc :javaType&gt;应该在绑定文件中用作&lt; jaxb :baseType&gt;的子元素。 我也错误地认为&lt; jaxb :baseType&gt;必须在LocaleType节点下定义,这不是真的。它必须在DelimitedSchemaType节点和FixedWidthSchemaType节点的元素节点下定义。像这样:

...
<jaxb:bindings node="//xs:complexType[@name='DelimitedSchemaType']">
    <jaxb:property>
        <jaxb:baseType>
            <xjc:javaType name="org.mylib.schema.LocaleType" adapter="org.mylib.schema.LocaleXmlAdapter"/>
        </jaxb:baseType>
    </jaxb:property>
</jaxb:bindings>
...

这应该是正确的,但不知何故,XJC编译器产生了编译错误。 发生以下错误:

[ERROR] Error while parsing schema(s).Location [ file:/C:/IdeaProjects/JaxbMarshalling/src/main/resources/dataschema.xjb{25,113}].
com.sun.istack.SAXParseException2; systemId: file:/C:/IdeaProjects/JaxbMarshalling/src/main/resources/dataschema.xjb; lineNumber: 25; columnNumber: 113; compiler was unable to honor this conversion customization. It is attached to a wrong place, or its inconsistent with other bindings.
    at com.sun.tools.xjc.ErrorReceiver.error(ErrorReceiver.java:86)
    etc.

它一直在唠叨“编译器无法遵守此转换定制。它附加到错误的地方,或者与其他绑定不一致。”,而绑定文件中没有错误被发现。

我已经改进了我的绑定文件,但仍然不是'正确'。我无法确定它出错的确切位置。

BTW:我使用以下工具:

  • Oracle Java JDK 64位,版本1.8.0_112-b15
  • xjc,版本2.2.8-b130911.1802(随上述JDK一起提供)
  • maven3,版本3.3.9
  • IntelliJ IDEA 2016.3,版本163.7743.44
  • maven-jaxb2-plugin,版本0.13.1

因为我现在几天都在苦苦挣扎,所以我已经开始了赏金。 真正使用外部绑定文件解决问题并更正注释的人获得我的赏金积分。

3 个答案:

答案 0 :(得分:3)

这个问题/问题有几个缺陷,首先必须解决,以便成功回答问题。 因为您要求详细的规范答案,解决所有问题,所以这里是:

首先,一些观察结果:

  1. DelimitedDataSchema.java和FixedWidthDataSchema.java都包含一个对象字段&#39; locale&#39;数据类型org.mylib.schema.LocaleType必须更正为java.util.Locale数据类型。
  2. 对象字段&#39; locale&#39;在DelimitedDataSchema.java和FixedWidthDataSchema.java中必须包含@XmlJavaTypeAdapter注释,现在不存在。
  3. 对象字段&#39; locale&#39;在DelimitedDataSchema.java和FixedWidthDataSchema.java中已经包含@XmlElement注释,现在它只指定了所需的注释。元件。它还必须包括&#39;类型&#39;元件。
  4. 将成为(联合国)编组的地区&#39; xml数据是complexType数据结构,即:LocaleType,只有三个xs:string类型的属性。当前的Xml Java编译器(= XJC)(尚未)支持将complexTypes处理为正确的注释。
  5. 外部绑定文件中的节点LocaleType包含错误定义的属性。 &#39; localeType&#39;只有三个属性,没有定义。
  6. 定义的LocaleXmlAdapter被错误定义,应该移动到DelimitedDataSchema和FixedWidthDataSchema类的属性(xml元素)。
  7. &lt; jaxb:baseType&gt;字段/元素&#39; locale&#39;的声明缺少DelimitedDataSchema和FixedWidthDataSchema类。
  8. 您没有在问题中指定maven pom.xml文件。下次问你的问题时也请包括这个。它为希望尽可能准确回答您问题的用户提供有价值的信息。即使对于处理同样问题的新求职者,也会在帖子中找到他们需要的答案。尽可能完整。
  9. 其次,一些修改/补充:

    1. 您的XML架构文件定义明确。因此,此文件不需要修改。
    2. 您的绑定文件(datasource.jxb)确实包含漏洞。
    3. 为了纠正这些缺陷,请执行以下操作:

      1. 建议:将LocaleType的类名重命名为XmlLocale,这样您就可以轻松地将XmlLocale.class和LocaleXmlAdapter.class匹配在一起,而不会混淆java.util.Locale和org.mylib.schema.Locale(这是现在重命名为org.mylib.schema.XmlLocale)
      2. 更正:完全删除元素和子元素,因为它们不能在LocaleType的级别指定,而是在&#39; locale的级别上指定。 DelimitedSchemaType和FixedWidthSchemaType中的元素。
      3. 更正:在complexType DelimitedSchemaType和FixedWidthSchemaType中定义一个代表&#39; locale&#39;的子XPath节点。这些complexTypes中指定的元素。
      4. 更正:放置在&#39; locale&#39;在complextType DelimitedSchemaType和FixedWidthSchemaType中定义的元素节点a&lt; jaxb:property&gt;带有子元素的元素&lt; jaxb:baseType&gt;元件。为该物业命名。它可以与XML Schema中指定的名称相同,但也可以以不同方式命名。如果您的名称与XML Schema不同,请注意您的对象字段的调用方式与&lt; jaxb:property&gt;类似。 name而不是XML Schema元素名称。这也会对getter和setter方法名称产生影响。
      5. 更正:使用&lt; jaxb:baseType&gt;定义属性的数据类型名称。有用对象字段数据类型的类型为java.util.Locale。因此,你得到:&lt; jaxb:baseType name =&#34; java.util.Locale&#34; /&gt;。您没有指定org.mylib.schema.XmlLocale数据类型作为名称!
      6. 此外:为了将@XmlJavaTypeAdapter添加到元素&#39; locale&#39;在DelimitedDataSchema和FixedWidthDataSchema类中,通常使用&lt; xjc:baseType&gt;来指定它。元件。但是因为Xml Java编译器(= XJC)还没有(还)处理这种类型的转换 complexTypes和Java数据类型,您不能使用文档中描述的默认规范。这对当前的XJC来说还不起作用:

        <jaxb:baseType>
            <xjc:javaType name="org.mylib.schema.XmlLocale" adapter="org.mylib.schema.LocaleXmlAdapter"/>
        </jaxb:baseType>
        

        因此,您必须自己提供@XmlJavaTypeAdapter注释。这就是jaxb2-basics-annotate插件[link]派上用场的地方。使用此插件,您可以在Java类中的任何位置注释任何现有Java注释:类级别,字段级别,方法级别等。 为了注释“失踪”。注释你必须设置一些东西,稍后将对此进行描述 在绑定文件中,您必须指定以下设置:
        a)在绑定文件的根目录中指定插件使用的命名空间(annox);
        b)在绑定文件的根目录中指定extensionBindingPrefixed;

        <jaxb:bindings jaxb:version="2.1" xmlns:xs="http://www.w3.org/2001/XMLSchema"
            xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
            xmlns:annox="http://annox.dev.java.net"
            schemaLocation="dataschema.xsd" node="/xs:schema"
            jaxb:extensionBindingPrefixes="xjc annox">
        

        c)使用元素指定首选注释。
        因为需要在对象字段&#39; locale&#39;上指定适配器。在DelimitedDataSchema和FixedWidthDataSchema类中,必须在&lt; jaxb:bindings&gt;中指定annotate元素。 &#39;区域设置的节点&#39;:

        <jaxb:bindings node="//xs:complexType[@name='DelimitedSchemaType']">
            <jaxb:class name="DelimitedDataSchema"/>
            <jaxb:bindings node=".//xs:element[@name='locale']">
                <jaxb:property name="locale">
                    <jaxb:baseType name="java.util.Locale" /> 
                </jaxb:property> 
                <annox:annotate target="field">
                    @javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter(value = org.mylib.schema.LocaleXmlAdapter.class)
                </annox:annotate>
            <jaxb:bindings> 
        </jaxb:bindings>
        

        同样适用于FixedWidthSchemaType complexType。请注意,必须指定FULL包名称和类名,包括注释参数!

      7. 建议:确保绑定文件中的所有节点都已指定并映射到XML Schema元素和属性。建议这样做是因为通过指定每个节点并为每个节点赋予绑定文件中的名称(可以与XML模式名称相同或不同) 确保生成的类,字段,getter / setter按照您喜欢的方式命名。当有人决定重命名XML Schema名称时,这会阻止大量的手动工作,这显然会导致重新编译java类和引用与其他程序不匹配(手动 书面)。例如:您手动编写的XmlAdapter类:LocaleXmlAdapter,它引用生成的XmlLocale类中的方法名称。您实际执行的操作是使用单个绑定文件将XML模式名称与Java名称分离。这可以节省你很多 麻烦以后(相信我:我已经看到它在不同的开发团队中多次发生)!那只是浪费宝贵的时间和金钱。完全指定此绑定文件后,您只需采用XML Schema节点的名称,Java端不会更改!

        您的绑定文件现在会生成这个完整的绑定文件:

        <?xml version="1.0" encoding="utf-8"?>
        <jaxb:bindings jaxb:version="2.1" xmlns:xs="http://www.w3.org/2001/XMLSchema"
               xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
               xmlns:annox="http://annox.dev.java.net"
               schemaLocation="dataschema.xsd" node="/xs:schema"
               jaxb:extensionBindingPrefixes="xjc annox">
        
            <jaxb:schemaBindings>
                <jaxb:package name="org.mylib.schema"/>
            </jaxb:schemaBindings>
        
            <jaxb:bindings node="//xs:complexType[@name='DelimitedSchemaType']">
                <jaxb:class name="DelimitedDataSchema"/>
                <jaxb:bindings node=".//xs:element[@name='locale']">
                    <jaxb:property name="locale">
                        <jaxb:baseType name="java.util.Locale" />
                    </jaxb:property>
                    <annox:annotate target="field">
                        @javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter(value = org.mylib.schema.LocaleXmlAdapter.class)
                    </annox:annotate>
                </jaxb:bindings>
            </jaxb:bindings>
        
             <jaxb:bindings node="//xs:complexType[@name='FixedWidthSchemaType']">
                <jaxb:class name="FixedWidthDataSchema"/>
                <jaxb:bindings node=".//xs:element[@name='locale']">
                    <jaxb:property name="locale">
                        <jaxb:baseType name="java.util.Locale"/>
                    </jaxb:property>
                    <annox:annotate target="locale">
                        @javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter(value = org.mylib.schema.LocaleXmlAdapter.class)
                    </annox:annotate>
                </jaxb:bindings>
            </jaxb:bindings>
        
            <jaxb:bindings node="//xs:complexType[@name='LocaleType']">
                <jaxb:class name="XmlLocale"/>
                <jaxb:bindings node=".//xs:attribute[@name='language']">
                    <jaxb:property name="language"/>
                </jaxb:bindings>
                <jaxb:bindings node=".//xs:attribute[@name='country']">
                    <jaxb:property name="country"/>
                </jaxb:bindings>
                <jaxb:bindings node=".//xs:attribute[@name='variant']">
                    <jaxb:property name="variant"/>
                </jaxb:bindings>
            </jaxb:bindings>
        </jaxb:bindings>
        

      8.  3.未指定maven pom.xml文件,但是已完成     这个主题的概述,也在这里提到。

        使用maven生成JAXB类时需要考虑一些事项。

        为了做正确的事情&#39;,请执行以下操作:     - 由于JAXB XJC特定于您编译和运行它的Java版本,因此您应指定必须编译的源版本和目标Java版本。这可以使用maven-compiler-plugin完成。      现在,您不必让XJC使用默认级别1.5版编译Java类,而是指定版本1.8。

            <?xml version="1.0" encoding="UTF-8"?>
            <project xmlns="http://maven.apache.org/POM/4.0.0"
                     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
                <modelVersion>4.0.0</modelVersion>
        
                <groupId>org.mylib</groupId>
                <artifactId>mytool</artifactId>
                <version>1.0-SNAPSHOT</version>
                <packaging>jar</packaging>
                <name>project-name</name>
        
                <properties>
                    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
                </properties>
        
                <build>
                    <resources>
                        <resource>
                            <directory>${pom.basedir}/src/main/resources</directory>
                        </resource>
                    </resources>
        
                    <plugins>
                        <plugin>
                            <groupId>org.apache.maven.plugins</groupId>
                            <artifactId>maven-compiler-plugin</artifactId>
                            <version>3.6.0</version>
                            <configuration>
                                <source>1.8</source>
                                <target>1.8</target>
                            </configuration>
                        </plugin>
        
                        <plugin>
                            <groupId>org.jvnet.jaxb2.maven2</groupId>
                            <artifactId>maven-jaxb2-plugin</artifactId>
                            <version>0.13.1</version>
                            <executions>
                                <execution>
                                    <phase>generate-sources</phase>
                                    <goals>
                                        <goal>generate</goal>
                                    </goals>
                                    <configuration>
                                        <!-- allow specific vendor extension bindings (jaxb:extensionBindingPrefixes) -->
                                        <extension>true</extension>
                                        <!-- Generate lots of output (for debug purposes) -->
                                        <verbose>true</verbose>
                                        <locale>en</locale>
                                        <specVersion>2.2</specVersion>
                                        <schemaLanguage>XMLSCHEMA</schemaLanguage>
        
                                        <schemaDirectory>src/main/resources</schemaDirectory>
                                        <schemaIncludes>
                                            <schemaInclude>dataschema.xsd</schemaInclude>
                                        </schemaIncludes>
        
                                        <bindingDirectory>src/main/resources</bindingDirectory>
                                        <bindingIncludes>
                                            <bindingInclude>dataschema.xjb</bindingInclude>
                                        </bindingIncludes>
        
                                        <generateDirectory>${project.build.directory}/generated-sources/jaxb2</generateDirectory>
                                        <args>
                                            <!-- covered by the jaxb2-basics-annotate plugin (YOU ONLY NEED THIS ONE IN YOUR SITUATION!) -->
                                            <arg>-Xannotate</arg>
                                            <!-- covered by the jaxb2-basics-plugin -->
                                            <arg>-Xsimplify</arg>
                                            <arg>-XtoString</arg>
                                            <arg>-Xequals</arg>
                                            <arg>-XhashCode</arg>
                                        </args>
                                        <plugins>
                                            <!-- plugin for generated toString, hashCode, equals methods -->
                                            <plugin>
                                                <groupId>org.jvnet.jaxb2_commons</groupId>
                                                <artifactId>jaxb2-basics</artifactId>
                                                <version>1.11.1</version>
                                            </plugin>
                                            <!-- plugin for adding specified annotations (YOU ONLY NEED THIS ONE IN YOUR SITUATION!) -->
                                            <plugin>
                                                <groupId>org.jvnet.jaxb2_commons</groupId>
                                                <artifactId>jaxb2-basics-annotate</artifactId>
                                                <version>1.0.2</version>
                                            </plugin>
                                        </plugins>
                                    </configuration>
                                </execution>
                            </executions>
                        </plugin>
                    </plugins>
                </build>
            </project>
        

        第三,一些结果(之前和之后):

        在绑定文件和maven pom.xml文件中进行修改之前执行maven编译阶段时,最终得到了以下DelimitedDataSchema类(显示了摘录):

        package org.mylib.schema;
        
        import javax.xml.bind.annotation.XmlAccessType;
        import javax.xml.bind.annotation.XmlAccessorType;
        import javax.xml.bind.annotation.XmlElement;
        import javax.xml.bind.annotation.XmlType;
        
        @XmlAccessorType(XmlAccessType.FIELD)
        @XmlType(name = "DelimitedSchemaType", propOrder = {
           "locale"
        })
        public class DelimitedDataSchema {
        
        @XmlElement(required = true)
        protected XmlLocale locale; // XmlLocale instead of Locale (java.util.Locale)
        
        }
        

        在绑定文件和maven pom.xml文件中进行修改后执行maven编译阶段时,最终得到了以下DelimitedDataSchema类(显示了摘录):

        package org.mylib.schema;
        
        import java.util.Locale;
        import javax.xml.bind.annotation.XmlAccessType;
        import javax.xml.bind.annotation.XmlAccessorType;
        import javax.xml.bind.annotation.XmlElement;
        import javax.xml.bind.annotation.XmlType;
        import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
        
        @XmlAccessorType(XmlAccessType.FIELD)
        @XmlType(name = "DelimitedSchemaType", propOrder = {
            "locale"
        })
        public class DelimitedDataSchema {
        
            @XmlElement(required = true, type = XmlLocale.class)
            @XmlJavaTypeAdapter(LocaleXmlAdapter.class)
            protected Locale locale;
        
        }   
        

        结果清楚:通过使用上述溶液完成所需的溶液。 请注意,@ xmlElement现在包含一个额外的参数:type = XmlLocale.class。 请注意,@ XmlJavaTypeAdapter仅包含LocaleXmlAdapter.class参数。 您也可以采用不同的方式编写相同的情况,例如:

        @XmlElement(required = true)
        @XmlJavaTypeAdapter(type = XmlLocale, value = LocaleXmlAdapter.class)
        

        完全相同。但请记住,您需要指定&lt; jaxb:baseType name =&#34; java.util.Locale&#34; /&gt;因为对象字段必须定义为java.util.Locale。目前,这是实现这一目标的唯一途径。您不能只使用jaxb2-basics-annotate插件指定@XmlJavaTypeAdapter(type = XmlLocale,value = LocaleXmlAdapter.class)注释,因为对象字段属性不会更改为java.util.Locale数据类型。

        在不久的将来,我希望Xml Java编译器(XJC)支持complexTypes,并通过检查自定义编写的XmlAdapter参数和返回类型来区分正在编组/解组的数据类型。

        第四,证据(编组和解编)

        有一种说法是:&#34;证明是在吃布丁&#34;,这意味着这样的事情:如果你创造了一些东西并且看起来很好,那么唯一的方法就是知道它是不是真的很好(即它有效)是通过测试它。在这种情况下编组/解组它。 在布丁的情况下,品尝它是绝对确保食谱很好的唯一方法!

        Main.java:

        package org.mylib;
        
        import org.mylib.schema.Dataschema;
        import org.mylib.schema.DelimitedDataSchema;
        import org.mylib.schema.FixedWidthDataSchema;
        
        import javax.xml.bind.JAXBContext;
        import javax.xml.bind.JAXBException;
        import javax.xml.bind.Unmarshaller;
        import javax.xml.transform.stream.StreamSource;
        import java.io.Reader;
        import java.io.StringReader;
        
        public class Main {
        
            public static void main(String[] args) throws Exception {
                Dataschema ds = null;
        
                Reader xmlFileDelimited = new StringReader("<dataschema>\n" +
                        "  <delimited>\n" +
                        "    <locale language=\"en\" country=\"us\" />\n" +
                        "  </delimited>\n" +
                        "</dataschema>");
        
                try {
                    JAXBContext jc = JAXBContext.newInstance(Dataschema.class);
                    Unmarshaller um = jc.createUnmarshaller();
                    ds = (Dataschema) um.unmarshal(new StreamSource(xmlFileDelimited));
                } catch (JAXBException e) {
                    e.printStackTrace();
                }
        
                if (ds == null) {
                    throw new NullPointerException("null literal as output of marshaller!");
                }
        
                DelimitedDataSchema delimited = ds.getDelimited();
                FixedWidthDataSchema fixedwidth = ds.getFixedwidth();
        
                if (((fixedwidth == null) && (delimited == null)) || ((fixedwidth != null) && (delimited != null))) {
                    throw new IllegalStateException("schemas cannot be both absent or be both present at the same time!"); // (because of <choice> xml schema)!
                }
        
                if (delimited != null) {
                    // very primitive code for proving correctness
                    System.out.println(delimited.getLocale().toString());
                }
        
                if (fixedwidth != null) {
                    // very primitive code for proving correctness
                    System.out.println(fixedwidth.getLocale().toString());
                }
            }
        }
        

        编组省略,留待读者实施。

        示例结束。

        请注意,JAXB本身很好地使用LocaleXmlAdapter编组和解组org.mylib.schema.XmlLocale和java.util.Locale。因此,在这种情况下,JAXB核心不是麻烦制造者。 Xml Java编译器是不接受complexTypes的原因。 这些是XJC目前的限制/缺点,有望在不久的将来得到解决!

        要考虑的最后一句话:如果人迹罕至的地方没有让你到达那里,那么就走那条路。缓慢而稳定地赢得比赛!

        一些脚注: 使用maven-compiler-plugin将源和目标编译器级别设置为1.8而不是1.5(这是默认值)。

        关于maven-compiler-plugin的重要说明: &#34;仅设置目标选项并不能保证您的代码实际上在具有指定版本的JRE上运行。缺陷是无意中使用的API,这些API仅存在于以后的JRE中,这会使您的代码在运行时因链接错误而失败。 要避免此问题,您可以配置编译器的引导类路径以匹配目标JRE,也可以使用Animal Sniffer Maven插件验证您的代码是否使用了非预期的API。 同样,设置source选项并不能保证您的代码实际上在具有指定版本的JDK上编译。 要使用特定的JDK版本编译代码,不同于用于启动Maven的版本,请参阅使用不同的JDK编译示例。&#34;

        请参阅:https://maven.apache.org/plugins/maven-compiler-plugin/examples/set-compiler-source-and-target.html

        换句话说:如果您想确保您的项目使用正确的Java版本并因此更正JAXB版本,请使用Animal Sniffer Maven插件。请参阅:http://www.mojohaus.org/animal-sniffer/animal-sniffer-maven-plugin/

        全部;)

答案 1 :(得分:1)

JAXB似乎仅在xml simple中支持<xjc:javaType>类型,因此您会看到错误&#34; ...unable to honor...&#34;。请参阅related question

如何在生成的类上生成@XmlJavaTypeAdapter注释。 (基于jaxb2-annotate-plugin

在绑定文件中指定@XmlJavaTypeAdapter,如下所示

<?xml version="1.0" encoding="utf-8"?>
<jaxb:bindings jaxb:version="2.1" xmlns:xs="http://www.w3.org/2001/XMLSchema"
               xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
               xmlns:annox="http://annox.dev.java.net"
               schemaLocation="dataschema.xsd" node="/xs:schema">

    <jaxb:schemaBindings>
        <jaxb:package name="org.mylib.schema">
            <jaxb:javadoc>
                Package level documentation for generated package org.mylib.schema.
            </jaxb:javadoc>
        </jaxb:package>
    </jaxb:schemaBindings>

    <jaxb:bindings node="//xs:complexType[@name='LocaleType']">
        <jaxb:class name="LocaleType"/>
        <jaxb:property>
            <jaxb:baseType name="java.util.Locale"/>
        </jaxb:property>
        <annox:annotate target="field">@javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter(org.mylib.schema.adaptors.LocaleXmlAdapter.class)</annox:annotate>
    </jaxb:bindings>

    <jaxb:bindings node="//xs:complexType[@name='DelimitedSchemaType']">
        <jaxb:class name="DelimitedDataSchema"/>
    </jaxb:bindings>

    <jaxb:bindings node="//xs:complexType[@name='FixedWidthSchemaType']">
        <jaxb:class name="FixedWidthDataSchema"/>
    </jaxb:bindings>
</jaxb:bindings>

将pom文件中的JAXB插件配置为:

<build>
        <plugins>
            <plugin>
                <groupId>org.jvnet.jaxb2.maven2</groupId>
                <artifactId>maven-jaxb2-plugin</artifactId>
                <configuration>
                    <extension>true</extension>
                    <args>
                        <arg>-Xannotate</arg>
                    </args>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.jvnet.jaxb2_commons</groupId>
                        <artifactId>jaxb2-basics-annotate</artifactId>
                        <version>1.0.2</version>
                    </dependency>
                </dependencies>
                <executions>
                    <execution>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

答案 2 :(得分:0)

您的两个Locale类之间存在类名冲突。

我通过进行以下更改来使您的代码正常工作。我没有从XML模式生成JAXB类,只是直接更新它们,因此您必须弄清楚如何更新绑定文件以获得此结果。

  • 重命名您的Locale课程,因此它不会与java.util.Locale发生冲突,例如重命名为LocaleType

  • org.mylib.schema.Locale中将org.mylib.schema.LocaleType更改为LocaleXmlAdapter 注意:您现在可以使用import语句,而不必完全限定代码中的类。

  • 确保DelimitedDataSchema使用java.util.Locale,例如它仍然在字段和方法声明中显示Locale,并导入java.util.Locale

  • @XmlJavaTypeAdapter(LocaleXmlAdapter.class)添加到locale的{​​{1}}字段。

现在可行。