Das Problem:java.util.Locale in JAXB Verwendung generierten Klassen mit XMLAdapter
Basierend auf der folgende Dokumentation von Oracle über die Verwendung des java.util.Locale vorgesehen: [Internationalization: Understanding Locale in the Java Platform] habe ich die folgende Frage im Zusammenhang mit JAXB und das Gebietsschema.
Ich habe eine XML-Datei, die wie folgt aussieht:
<?xml version="1.0" encoding="utf-8"?>
<dataschema>
<delimited>
<locale language="en" country="US" variant="SiliconValley" />
</delimited>
</dataschema>
die auf den folgenden XML-Schema basiert:
<?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>
Das Problem ist jetzt, dass ich die folgenden generierten Klassen für das bekommen LocaleType xml complexType, der den tatsächlichen java.util.Locale-Datentyp in der generierten DelimitedDataSchema-Klasse nicht zu reflektieren scheint. Ich hätte erwartet, dass dies vom Typ java.util.Locale und nicht vom Typ org.mylib.schema.LocaleType wäre.
Die generierten Klassen von JAXB 2.x sind:
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:
Ich folgte tapfer die Anweisungen in den folgenden Blog-Beiträge von Blaise Doughan über JAXB XmlAdapters: JAXB and Package Level XmlAdapters und auch XmlAdapter - JAXB's Secret Weapon
So habe ich eine XMLAdapter mich der Hoffnung, dass die erzeugte Klasse (DelimitedDataSchema) die Java enthalten würde .util.Locale gibt den Datentyp im Getter und den java.util.Locale-Parameterdatentyp im Setter zurück. Was ich fälschlicherweise angenommen habe.
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;
}
}
die JAXB Bibliothek wissen zu lassen, dass sie die LocaleXmlAdapter verwenden müssen, sofern ich die Bibliothek mit einer externen Bindungs Datei, in der die LocaleXmlAdapter für die Locale-Klasse definiert ist .
Externe JAXB Einbindemappe:
<?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>
Nun ist der seltsame Teil, die ich nicht bekommen, ist offensichtlich, dass ich erwartet hätte, dass die JAXB Bibliothek den org.mylib.schema.LocaleType Typen übersetzen würde in den java.util.Locale Typ für die DelimitedDataSchema Klasse, so würden Sie die folgende Methode Signaturen in der DelimitedDataSchema-Klasse:
öffentliche java.util.Locale getLocale() {}
public void setLocale (java.util.Locale-Wert) {}
Was ich will zu tun ist, dass der java.util.Locale Datentyp anstelle des org.mylib.schema.LocaleType Datentyp verwendet wird. Wie bekomme ich sonst die Übersetzung zwischen dem Benutzercode und dem JAXB generierten Code? Ich kann die LocaleXmlAdapter-Klasse nicht selbst aufrufen, um den Gebietsschematyp für mich zu übersetzen, der von der JAXB-Bibliothek ausgeführt werden muss, aber ich möchte: getLocale() aufrufen und dafür einen java.util.Locale-Datentyp abrufen.
Was mache ich "falsch"?
Update:
Bisher habe ich herausgefunden, dass die < jaxb: basetype/> sollten nicht verwendet werden. Statt der < xjc: > basetype: javatype > sollte in der Bindungsdatei als untergeordnetes Element von < jaxb verwendet werden. Ich nahm auch fälschlicherweise an, dass die < jaxb: baseType > unter dem LocaleType-Knoten definiert werden musste, was NICHT wahr ist. Sie muss unter dem Elementknoten des DelimitedSchemaType-Knotens und des FixedWidthSchemaType-Knotens definiert werden. Gefällt mir:
...
<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>
...
Das sollte korrekt sein, aber irgendwie hat der XJC-Compiler Kompilierfehler erzeugt. Der folgende Fehler tritt auf: „. Compiler nicht in der Lage war, diese Umwandlung Anpassung zu ehrt Es wird zu einer falschen Stelle angebracht ist, oder sein inkonsistent mit anderen Bindungen“
[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.
Es hält Gezeter über , während es keinen Fehler gibt, innerhalb der Bindungsdatei zu finden.
Ich habe meine Bindungsdatei verbessert, aber immer noch ist etwas nicht "richtig". Ich kann den genauen Ort, an dem es falsch läuft, nicht genau bestimmen.
BTW: Ich nehme die folgenden Tools verwenden:
- Oracle Java JDK 64-Bit-Version 1.8.0_112-b15
- xjc, Version 2.2.8-b130911.1802 (mit oben genannten ausgeliefert JDK)
- maven3, Version 3.3.9
- IntelliJ IDEA 2016,3, Version 163.7743.44
- maven-jaxb2-Plugin, Version 0.13.1
Weil ich jetzt seit ein paar Tagen damit zu kämpfen habe, habe ich ein Kopfgeld begonnen. Die Person, die wirklich löst das Problem mit der externen Bindings-Datei und korrekte Anmerkungen erhalten meine Bounty-Punkte.
Beeindruckende Antwort! Ich habe es jetzt funktioniert. Endlich! Danke für Ihr Bemühen. – user504342
Gern geschehen! XJC kann manchmal eine Herausforderung sein. – CookingWithJava