2016-11-21 207 views
2

問題:在JAXB使用java.util.Locale中生成的類使用XmlAdapter

基於甲骨文有關使用java.util.Locale中提供的下列文件上:[Internationalization: Understanding Locale in the Java Platform],我有相關的以下問題JAXB和語言環境。

我有一個看起來像這樣的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和NOT類型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; 
    } 
} 

我勇敢地跟着從布萊斯Doughan以下博客張貼關於JAXB XmlAdapters說明:JAXB and Package Level XmlAdapters,也XmlAdapter - JAXB's Secret Weapon

所以我創建了一個XmlAdapter自己,希望生成的類(DelimitedDataSchema)將包含Java .util.Locale返回getter中的數據類型和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,我提供了一個外部綁定文件庫,其中LocaleXmlAdapter爲Locale類中定義。

外部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類型進入java.util.Locale中鍵入DelimitedDataSchema類,所以你會看到下面的方法簽名在DelimitedDataSchema類:

  • 公共java.util.Locale中的getLocale(){}

  • public void setLocale(java.util。區域設置值){}

我想做到的是,java.util.Locale中的數據類型來代替org.mylib.schema.LocaleType數據類型。如何在用戶代碼和JAXB生成的代碼之間完成翻譯?我無法自己調用LocaleXmlAdapter類來爲我轉換語言環境類型,這必須由JAXB庫完成,但我確實想調用:getLocale()並返回一個java.util.Locale數據類型。

我在做什麼'錯誤'?

更新:

到目前爲止,我想通了,在< JAXB:BASETYPE/>不應該被使用。而不是< xjc:javaType >應該在綁定文件中用作子元素< jaxb:baseType >。 我也錯誤地認爲必須在LocaleType節點下定義< jaxb:baseType >,這是不正確的。它必須在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:我使用以下工具:

  • 甲骨文的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-插件,版本0.13.1

因爲我現在爲此掙扎了好幾天,所以我開始了賞金。 確實使用外部綁定文件解決了問題,正確的註釋獲得我的賞金點。

回答

3

這個問題/問題有幾個缺陷首先必須解決問題才能成功回答問題。 因爲你要求一個詳細的規範答案,它解決所有問題,那就是:

首先,一些意見:

  1. 的DelimitedDataSchema.java和FixedWidthDataSchema.java都包含的一個目標領域「區域」數據類型org.mylib.schema.LocaleType必須更正爲java.util.Locale數據類型。
  2. DelimitedDataSchema.java和FixedWidthDataSchema.java中的對象字段'locale'必須包含@XmlJavaTypeAdapter註釋,該註釋現在不存在。
  3. DelimitedDataSchema.java和FixedWidthDataSchema.java中的對象字段'locale'已包含@XmlElement註釋,該註釋現在僅指定'required'元素。它還必須包含'type'元素。
  4. 要被(un)編組的'locale'xml數據是一個complexType數據結構,即:LocaleType,只有三個xs:string類型的屬性。當前的Xml Java Compiler(= XJC)尚未支持複雜類型被處理成正確的註釋。
  5. 外部綁定文件中的節點LocaleType包含錯誤定義的屬性。 'localeType'只有三個屬性,沒有定義。
  6. 定義的LocaleXmlAdapter被錯誤地定義的,並且應該被移動到屬性(XML元素)的DelimitedDataSchema和FixedWidthDataSchema類的。
  7. < jaxb:baseType >缺少對DelimitedDataSchema和FixedWidthDataSchema類中的字段/元素'locale'的聲明。
  8. 您還沒有指定你的Maven pom.xml文件在你的問題。請在下次提問時加入。它爲希望儘可能精確地回答您的問題的用戶提供有價值的信息。即使對於新的求職者應對同樣的問題,他們也會在你的帖子中找到他們需要的答案。儘可能完整。

其次,一些修改/添加:

  1. XML模式文件被明確定義。所以,這個文件不需要修改。
  2. 你綁定文件(datasource.jxb)確實包含缺陷。

爲了糾正這些缺陷,請執行下列操作:

  1. 推薦:LocaleType的類名稱重命名爲XmlLocale,讓您可以輕鬆匹配XmlLocale.class和LocaleXmlAdapter.class在一起,沒有java.util.Locale中和org.mylib.schema.Locale(現在更名爲org.mylib.schema.XmlLocale)
  2. 校正之間感到困惑:完全刪除元素和子元素,因爲這些不能指定在LocaleType級別,但是在DelimitedSchemaType和FixedWidthSchemaType中的'locale'元素的級別。
  3. 校正:內的complexType DelimitedSchemaType和FixedWidthSchemaType定義表示在這些複合類型中指定的「區域」的元素的子節點的XPath。
  4. 校正:與孩子< JAXB屬性>元件:鹼基類型>元件的complextType DelimitedSchemaType和FixedWidthSchemaType內限定的< JAXB的「區域」的元素節點下發生。給該物業一個名稱。這可以與XML模式中指定的名稱相同,但也可以用不同的名稱命名。如果您將其命名爲與XML Schema不同的名稱,請注意您的對象字段的名稱如< jaxb:property >名稱,而不是XML Schema元素名稱。這也對getter和setter方法名稱有影響。
  5. 更正:使用< jaxb:baseType >名稱定義屬性的數據類型。想要的對象字段數據類型是java.util.Locale類型。這樣你可以獲得:< JAXB:BASETYPE名= 「java.util.Locale中的」/ >。您不指定org.mylib.schema.XmlLocale數據類型作爲名稱!
  6. 另外:爲了將@XmlJavaTypeAdapter添加到DelimitedDataSchema和FixedWidthDataSchema類中的元素'locale'中,通常會使用< xjc:baseType >元素指定此值。但是由於Xml Java Compiler(= 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)使用元素指定首選註釋。
    因爲該適配器需要對所述DelimitedDataSchema和FixedWidthDataSchema班,註釋元件必須在< JAXB內指定的物場「區域」的指定:綁定>節點的「區域」的:

    <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。請注意,必須指定完整的包名稱和類名稱,包括註釋參數!

  7. 建議:確保綁定文件中的所有節點都已指定並映射到XML模式元素和屬性。建議這樣做,因爲通過指定每個節點併爲綁定文件 中的每個節點指定一個名稱(可以與XML模式名稱相同或不同),請確保生成的類,字段,getter/setters被命名爲YOU喜歡它。當稍後有人決定重命名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> 
    


3.沒有指定你的Maven的pom.xml文件,但對於這個話題的完整 概述,它這裏也提到了。

使用maven生成JAXB類時需要注意幾點。

爲了做正確的事情,請執行以下操作: - 由於JAXB XJC特定於您編譯和運行的Java版本,因此您應指定必須編譯的源版本和目標Java版本。這可以用maven-compiler-plugin來完成。 您現在指定版本1.8,而不是讓XJC編譯具有默認級別版本1.5的Java類。

<?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的編譯階段綁定修改之前文件和Maven pom.xml文件,你結束了以下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) 

} 

當執行行家編譯階段中的綁定修改後文件和行家pom.xml文件,則結束了與以下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) 

其中完成完全相同。但請記住,您需要指定< jaxb:baseType name =「java.util.Locale」/ >,因爲對象字段必須定義爲java.util.Locale。目前,這是完成此任務的唯一方法。您不能僅僅使用jaxb2-basics-annotate插件指定@XmlJavaTypeAdapter(type = XmlLocale,value = LocaleXmlAdapter.class)註釋,因爲對象字段屬性不會更改爲java.util.Locale數據類型。在不久的將來,我希望Xml Java編譯器(XJC)將支持complexTypes,並通過檢查自定義寫入的XmlAdapter參數和返回類型來區分被編組/解組自身的數據類型。

四,證據(打包和解包)

有一種說法,說:「證據是在布丁的飲食」,這意味着這樣的事情:如果你已經創建的東西,它看起來好,只有通過測試才能知道它是否真的有效。在這種情況下編組/編組它。 在布丁的情況下,品嚐它是絕對確保食譜非常好的唯一方法!

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的限制/缺點,希望能在不久的將來得到解決!

最後一句要考慮的事情:如果打敗的道路不能讓你在那裏,那就走這條路。踏實和穩重是贏得比賽的關鍵!

一些腳註: 將源和目標編譯器級別設置爲1.8而不是1。5(這是默認值)使用maven-compiler-plugin。

有關maven-compiler-plugin的重要注意事項: 「僅僅設置目標選項並不能保證你的代碼實際上運行在帶有指定版本的JRE上,這個缺陷是無意使用僅存在於後來的JRE中的API這會使你的代碼在運行時出現鏈接錯誤 爲了避免這個問題,你可以配置編譯器的引導類路徑來匹配目標JRE,或者使用Animal Sniffer Maven Plugin來驗證你的代碼不使用非預期的API。 同樣,設置source選項並不能保證你的代碼實際上是在指定版本的JDK上編譯的 要用特定的JDK版本編譯你的代碼,與用來啓動Maven的版本不同,請參考編譯用一個不同的JDK示例。「

參見:https://maven.apache.org/plugins/maven-compiler-plugin/examples/set-compiler-source-and-target.html

換句話說:如果你要確保你的項目使用了正確的Java版本,因此正確的JAXB版本,使用動物嗅探Maven插件。請參閱:http://www.mojohaus.org/animal-sniffer/animal-sniffer-maven-plugin/

這一切;)

+0

令人印象深刻的答案!我現在開始工作了。最後!感謝您的努力。 – user504342

+0

不客氣! XJC有時可能具有挑戰性。 – CookingWithJava

0

您的兩個Locale類之間存在類名衝突。

我通過進行以下更改而使代碼正常工作。我沒有從XML模式生成JAXB類,而是直接更新它們,所以你必須弄清楚如何更新綁定文件來獲得這個結果。

  • 重命名Locale類,所以它不會java.util.Locale,例如衝突重命名爲LocaleType

  • org.mylib.schema.Locale更改爲org.mylib.schema.LocaleType,LocaleXmlAdapter
    注意:您現在可以使用導入語句,而不必完全限定代碼中的類。

  • 確保DelimitedDataSchema使用java.util.Locale,例如,它在字段和方法聲明中仍然說明Locale,並且它會導入java.util.Locale

  • @XmlJavaTypeAdapter(LocaleXmlAdapter.class)添加到locale字段DelimitedDataSchema

現在,它的工作。

+0

安德烈亞斯嗨,我已經採取步驟1和2成功,步驟3和4在我的身邊作祟。我不知道如何使用綁定文件在DelimitedDataSchema類中添加註釋(在第4步中提到)。我必須使用綁定文件。我在前面有「用於XML綁定的Java體系結構(JAXB)2.2最終版本」規範,但我可能正在查看錯誤的部分? – user504342

+0

我嘗試了你的建議,它只有在生成後編輯生成的java文件並添加@XmlJavaTypeAdapter(value = LocaleXmlAdapter.class)時才起作用。我需要能夠生成Java文件,而無需手動編輯它們。問題在於導致錯誤:「編譯器無法兌現此轉換定製它附屬於錯誤的地方,或者與其他綁定不一致「。爲什麼這不起作用? – user504342

+0

謝謝你的幫助安德烈亞斯。我使用用戶'CookingWithJava'給出的答案來工作。最後! – user504342

1

JAXB似乎只支持xml simple類型只在<xjc:javaType>,因此你看到錯誤「...unable to honor...」。請參閱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> 

配置JAXB插件在你的POM文件爲:

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

XmlJavaTypeAdapter批註放置在LocaleType中,它必須移動到區域節點下的DelimitedSchemaType和FixedWidthSchemaType節點,如用戶'CookingWithJava'所述。無論如何感謝您的幫助。 – user504342