問題:在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
因爲我現在爲此掙扎了好幾天,所以我開始了賞金。 確實使用外部綁定文件解決了問題,正確的註釋獲得我的賞金點。
令人印象深刻的答案!我現在開始工作了。最後!感謝您的努力。 – user504342
不客氣! XJC有時可能具有挑戰性。 – CookingWithJava