[英]Using java.util.Locale in JAXB generated classes using XmlAdapter
The problem: 问题:
Based on the following documentation provided by Oracle about the use of the java.util.Locale: [Internationalization: Understanding Locale in the Java Platform] , I have the following question related to JAXB and the Locale. 基于Oracle提供的有关使用java.util.Locale的以下文档: [国际化:了解Java平台中的语言环境] ,我有以下与JAXB和语言环境有关的问题。
I have an XML file that looks like this: 我有一个看起来像这样的XML文件:
<?xml version="1.0" encoding="utf-8"?>
<dataschema>
<delimited>
<locale language="en" country="US" variant="SiliconValley" />
</delimited>
</dataschema>
Which is based on the following XML schema: 它基于以下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>
Now the problem is that I get the following generated classes for the LocaleType xml complexType which does not seem to reflect the actual java.util.Locale datatype within the generated DelimitedDataSchema class. 现在的问题是,我为LocaleType xml complexType获取了以下生成的类,该类似乎无法反映生成的DelimitedDataSchema类中的实际java.util.Locale数据类型。 I would have expected this to be of type java.util.Locale and NOT of type org.mylib.schema.LocaleType?
我曾希望这是java.util.Locale类型,而不是org.mylib.schema.LocaleType类型?
The generated classes by JAXB 2.x are: JAXB 2.x生成的类是:
Dataschema.java: 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: 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: 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;
}
}
I bravely followed the instructions in the following blog posts from Blaise Doughan about JAXB XmlAdapters: JAXB and Package Level XmlAdapters and also XmlAdapter - JAXB's Secret Weapon 我勇敢地遵循了Blaise Doughan在以下博客文章中有关JAXB XmlAdapters的指示: JAXB和程序包级别XmlAdapters以及XmlAdapter-JAXB的秘密武器
So I created an XmlAdapter myself, hoping that the generated class (DelimitedDataSchema) would contain the java.util.Locale return datatype in the getter and the java.util.Locale parameter datatype in the setter. 因此,我自己创建了一个XmlAdapter,希望生成的类(DelimitedDataSchema)在getter中包含java.util.Locale返回数据类型,在setter中包含java.util.Locale参数数据类型。 Which I mistakenly assumed.
我错误地假设了。
LocaleXmlAdapter.java: 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;
}
}
To let the JAXB library know that it must use the LocaleXmlAdapter, I provided the library with an external binding file, in which the LocaleXmlAdapter is defined for the Locale class. 为了让JAXB库知道它必须使用LocaleXmlAdapter,我为该库提供了一个外部绑定文件,其中为Locale类定义了LocaleXmlAdapter。
External JAXB binding file: 外部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>
Now the weird part, which I obviously don't get, is that I would have expected that the JAXB library would translate the org.mylib.schema.LocaleType type into the java.util.Locale type for the DelimitedDataSchema class, so you would see the following method signatures in the DelimitedDataSchema class: 现在,我显然不会得到的怪异部分是,我希望JAXB库将org.mylib.schema.LocaleType类型转换为DelimitedDataSchema类的java.util.Locale类型,因此您将请参见DelimitedDataSchema类中的以下方法签名:
public java.util.Locale getLocale() {} 公共java.util.Locale getLocale(){}
public void setLocale(java.util.Locale value) {} public void setLocale(java.util.Locale value){}
What I want to accomplish is that the java.util.Locale datatype is used instead of the org.mylib.schema.LocaleType datatype. 我要完成的工作是使用java.util.Locale数据类型而不是org.mylib.schema.LocaleType数据类型。 How else do I get the translation done between the user code and the JAXB generated code?
如何在用户代码和JAXB生成的代码之间进行转换? I can't call the LocaleXmlAdapter class myself to translate the locale type for me, that must be done by the JAXB library, but I do want to call: getLocale() and in return get a java.util.Locale datatype.
我不能自己调用LocaleXmlAdapter类来为我转换语言环境类型,这必须由JAXB库完成,但是我确实要调用:getLocale()并返回一个java.util.Locale数据类型。
What am I doing 'wrong'? 我究竟做错了什么'?
Update: 更新:
So far I figured out that the < jaxb :baseType /> should NOT be used. 到目前为止,我发现不应使用< jaxb :baseType />。 Instead the < xjc :javaType > should be used within the binding file as a child element of < jaxb :baseType>.
相反,< xjc :javaType>应该在绑定文件中用作< jaxb :baseType>的子元素。 I also falsely assumed that the < jaxb :baseType> had to be defined under the LocaleType node, which is NOT true.
我还错误地假定< jaxb :baseType>必须在LocaleType节点下定义,这是不正确的。 It must be defined under the element node of the DelimitedSchemaType node and FixedWidthSchemaType node.
它必须在DelimitedSchemaType节点和FixedWidthSchemaType节点的元素节点下定义。 Like this:
像这样:
...
<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>
...
This should be correct, but somehow the XJC compiler produced compile errors. 这应该是正确的,但是XJC编译器某种程度上会产生编译错误。 The following error occurs:
发生以下错误:
[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.
It keeps nagging about "compiler was unable to honor this conversion customization. It is attached to a wrong place, or its inconsistent with other bindings." 它一直在抱怨“编译器无法执行此转换自定义。它被附加到错误的位置,或者与其他绑定不一致。” , while there is no mistake within the bindings file to be found.
,而在绑定文件中没有发现错误。
I have improved my bindings file, but still something isn't 'right'. 我已经改进了绑定文件,但是仍然有些不正确。 I can't pinpoint the exact location where it goes 'wrong'.
我无法查明“错误”的确切位置。
BTW: I am using the following tools: 顺便说一句:我正在使用以下工具:
Because I am struggling with this for a few days now, I have started a bounty. 由于我为此苦苦挣扎了几天,所以我开始了赏金计划。 The person that really solves the problem using the external bindings file and correct annotations gets my bounty points.
使用外部绑定文件和正确的注释真正解决问题的人会得到我的赏识。
This question/problem has several flaws in it that first must be addressed in order to successfully answer the question/problem. 这个问题/问题有几个缺陷,必须首先解决该问题才能成功回答该问题/问题。 Because you requested a detailed canonical answer, which addresses ALL concerns, here it is:
由于您要求提供详细的规范答案,以解决所有问题,因此这里是:
First, some observations: 首先,一些观察:
Second, some modifications/addition: 第二,一些修改/添加:
In order to correct these flaws, do the following: 为了纠正这些缺陷,请执行以下操作:
addition: In order to add the @XmlJavaTypeAdapter to the element 'locale' in DelimitedDataSchema and FixedWidthDataSchema classes, you normally would specify this using the <xjc:baseType> element. 另外:为了将@XmlJavaTypeAdapter添加到DelimitedDataSchema和FixedWidthDataSchema类中的元素“ locale”,通常可以使用<xjc:baseType>元素进行指定。 But because the Xml Java Compiler (=XJC) does NOT (yet) handle this type of conversion between complexTypes and Java datatypes, you cannot use the default specification as described in the documentation.
但是,由于Xml Java编译器(= XJC)尚未(尚未)处理complexType和Java数据类型之间的这种类型的转换,因此您不能使用文档中所述的默认规范。 This just doesn't work (yet) with the current XJC:
这对于当前的XJC仍然不起作用:
<jaxb:baseType> <xjc:javaType name="org.mylib.schema.XmlLocale" adapter="org.mylib.schema.LocaleXmlAdapter"/> </jaxb:baseType>
So you must provide the @XmlJavaTypeAdapter annotation yourself. 因此,您必须自己提供@XmlJavaTypeAdapter批注。 This is where the jaxb2-basics-annotate plugin [link] comes in handy.
这是jaxb2-basics-annotate插件[link]派上用场的地方。 With this plugin you can annotate ANY existing Java annotation at any location within a Java class: class-level, field-level, method-level, etc. In order to annotate the 'missing' annotation you have to set up a few things, which are described later on.
使用此插件,您可以在Java类中的任何位置注释任何现有的Java注释:类级别,字段级别,方法级别等。为了注释“缺失”注释,您必须进行一些设置,稍后将对此进行描述。
In the bindings file you have to specify the following settings: 在绑定文件中,您必须指定以下设置:
a) specify the namespace (annox) used by the plugin in the root of your bindings file; a)在绑定文件的根目录中指定插件使用的名称空间(annox);
b) specify the extensionBindingPrefixed in the root of your bindings file; 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) specify the preferred annotation using the element. c)使用元素指定首选注释。
Because the adapter needs to be specified on the object field 'locale' of the DelimitedDataSchema and FixedWidthDataSchema classes, the annotate element must be specified within the <jaxb:bindings> node of the 'locale': 因为需要在DelimitedDataSchema和FixedWidthDataSchema类的对象字段“ locale”上指定适配器,所以必须在“ locale”的<jaxb:bindings>节点内指定注释元素:
<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>
Likewise for the FixedWidthSchemaType complexType. 对于FixedWidthSchemaType complexType同样。 Notice that the FULL package name and class name, including the annotation parameter(s) must be specified!
注意,必须指定FULL包名和类名,包括注释参数!
recommendation: make sure that all your nodes within the bindings file are specified and mapped to the XML Schema elements and attributes. 建议:确保已指定绑定文件中的所有节点并将其映射到XML Schema元素和属性。 This is recommended because by specifying each node and giving each node a name (can be the same or different than the XML Schema name) in the bindings file you make sure that the generated classes, fields, getters/setters are named the way YOU like it.
推荐这样做是因为通过在绑定文件中指定每个节点并为每个节点指定名称(可以与XML Schema名称相同或不同),可以确保生成的类,字段,getter / setter的命名方式如您所愿它。 This prevents a lot of manual work later on, when someone decides to rename the XML Schema names, which obviously leads to recompiling of java classes and reference mismatched with other (manually written) classes.
当有人决定重命名XML Schema名称时,这将阻止以后进行大量手动工作,这显然会导致Java类的重新编译以及与其他(手动编写的)类不匹配的引用。 For example: your manually written XmlAdapter class: LocaleXmlAdapter, which refers to method names in the generated XmlLocale class.
例如:您手动编写的XmlAdapter类:LocaleXmlAdapter,它引用生成的XmlLocale类中的方法名称。 What you actually do is decouple the XML Schema names from the Java names using one single binding file.
您实际上所做的是使用一个绑定文件将XML模式名称与Java名称分离。 That saves you from a lot of trouble later on (trust me: I've seen it happen many times in different development teams)!
这样一来,您就免除了以后的麻烦(相信我:我已经在不同的开发团队中看到了很多次)! That is just wasting valuable time and money.
那只是浪费宝贵的时间和金钱。 With this binding file fully specified, you only have to adopt the name of the XML Schema node, the Java-side does not change!
完全指定此绑定文件后,您只需采用XML Schema节点的名称,Java端就不会改变!
Your binding file now results in this complete bindings file: 现在,您的绑定文件将生成以下完整的绑定文件:
<?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. Your maven pom.xml file is not specified, but for the complete overview of this topic, it is mentioned here as well. 3.未指定您的maven pom.xml文件,但是为了完整了解本主题,此处也将其提及。
There are a few things to take into consideration when generating JAXB classes using maven. 使用maven生成JAXB类时,需要考虑一些事项。
In order to do the 'right thing', do the following: - Since JAXB XJC is specific on which Java version you compile and run it, you should specify to which source and target Java version it must be compiled. 为了做“正确的事情”,请执行以下操作:-由于JAXB XJC专门针对您编译和运行的Java版本,因此您应指定必须将其编译到的源Java版本和目标Java版本。 This can be accomplished with the maven-compiler-plugin.
这可以通过maven-compiler-plugin完成。 Instead of letting XJC compile the Java classes with default level, version 1.5, you now specify version 1.8.
现在,您可以指定版本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>
Third, some results (before and after): 第三,一些结果(之前和之后):
When executing the maven compile phase before the modifications in the bindings file and maven pom.xml file, you ended up with the following DelimitedDataSchema class (excerpt is shown): 在绑定文件和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)
}
When executing the maven compile phase after the modifications in the bindings file and maven pom.xml file, you ended up with the following DelimitedDataSchema class (excerpt is shown): 在对绑定文件和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;
}
The result is clear: the desired solution is accomplished by using the above mentioned solution. 结果很明显:使用上述解决方案即可实现所需的解决方案。 Notice that the @XmlElement now contains an extra parameter: type = XmlLocale.class.
请注意,@ XmlElement现在包含一个额外的参数:type = XmlLocale.class。 Notice that the @XmlJavaTypeAdapter only contains the LocaleXmlAdapter.class parameter.
请注意,@ XmlJavaTypeAdapter仅包含LocaleXmlAdapter.class参数。 You can also write the same situation differently, like:
您还可以不同地编写相同的情况,例如:
@XmlElement(required = true)
@XmlJavaTypeAdapter(type = XmlLocale, value = LocaleXmlAdapter.class)
Which accomplishes exactly the same. 哪个完全一样。 But remember that you need to specify the <jaxb:baseType name="java.util.Locale"/> because the object field must be defined as java.util.Locale.
但是请记住,您必须指定<jaxb:baseType name =“ java.util.Locale” />,因为对象字段必须定义为java.util.Locale。 Currently, this is the ONLY way to accomplish this.
当前,这是完成此操作的唯一方法。 You cannot just ONLY specify the @XmlJavaTypeAdapter(type = XmlLocale, value = LocaleXmlAdapter.class) annotation using the jaxb2-basics-annotate plugin because the object field property is then NOT changed into the java.util.Locale datatype.
您不能仅使用jaxb2-basics-annotate插件指定@XmlJavaTypeAdapter(type = XmlLocale,value = LocaleXmlAdapter.class)批注,因为对象字段属性随后不会更改为java.util.Locale数据类型。
In the near future I hope the Xml Java Compiler (XJC) will support complexTypes and distinguishes the datatypes being marshalled/unmarshalled itself by inspecting the custom written XmlAdapter parameter and return types. 我希望在不久的将来,Xml Java编译器(XJC)将支持complexTypes,并通过检查自定义编写的XmlAdapter参数和返回类型来区分被编组/解组的数据类型。
Fourth, the evidence (Marshalling and Unmarshalling) 四,证据(编组和拆组)
There is a saying that says: "The proof is in the eating of the pudding", which means something like this: if you have created something and it looks good, the only way to know if it really is good (ie that it works) is by testing it. 有一句话说:“证明是在吃布丁”,意思是这样的:如果您创造了某种东西,并且看起来不错,那么唯一的办法就是知道它是否真的很好(即,它有效) )通过测试。 In this case marshalling/unmarshalling it.
在这种情况下,将其进行编组/解组。 In the case of the pudding, tasting it is the only way to be absolutely sure the recipe is great!
在布丁的情况下,品尝它是绝对可以确保食谱很棒的唯一方法!
Main.java: 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());
}
}
}
Marshalling omitted, that is left to the reader to implement. 编组省略,即留给读者实施。
End of example. 示例结束。
Note that JAXB itself DOES marshal and unmarshal the org.mylib.schema.XmlLocale and java.util.Locale using the LocaleXmlAdapter pretty well. 请注意,JAXB本身确实很好地使用LocaleXmlAdapter对org.mylib.schema.XmlLocale和java.util.Locale进行了编组和解组。 So, it is not the JAXB core that is the troublemaker in this case.
因此,在这种情况下,麻烦者不是JAXB核心。 The Xml Java Compiler is the one to blame for not accepting complexTypes (yet).
Xml Java编译器是尚未接受complexTypes的罪魁祸首。 These are the current limitations/shortcommings of the XJC and will hopefully be solved in the near future!
这些是XJC当前的局限性/不足之处,并有望在不久的将来得到解决!
Last words to consider: If the beaten path doesn't get you there, then take the road that does. 最后要考虑的问题:如果人迹罕至的地方无法带您到达目的地,那就走那条路。 Slow and steady wins the race!
踏实和稳重是赢得比赛的关键!
Some footnotes: Set the source and target compiler level to 1.8 instead of 1.5 (which is the default) using the maven-compiler-plugin. 一些脚注:使用maven-compiler-plugin将源和目标编译器级别设置为1.8,而不是1.5(这是默认设置)。
Important note concerning the maven-compiler-plugin: "Merely setting the target option does not guarantee that your code actually runs on a JRE with the specified version. The pitfall is unintended usage of APIs that only exist in later JREs which would make your code fail at runtime with a linkage error. To avoid this issue, you can either configure the compiler's boot classpath to match the target JRE or use the Animal Sniffer Maven Plugin to verify your code doesn't use unintended APIs. In the same way, setting the source option does not guarantee that your code actually compiles on a JDK with the specified version. To compile your code with a specific JDK version, different than the one used to launch Maven, refer to the Compile Using A Different JDK example." 关于maven-compiler-plugin的重要说明:“仅设置目标选项并不能保证您的代码实际在具有指定版本的JRE上运行。陷阱在于,只有在以后的JRE中才存在的API意外使用,它们会使您的代码成为现实。为了避免此问题,您可以在运行时失败,为避免此问题,您可以配置编译器的引导类路径以匹配目标JRE,也可以使用Animal Sniffer Maven插件来验证您的代码没有使用意外的API。 source选项不能保证您的代码实际上可以在具有指定版本的JDK上进行编译。要使用特定的JDK版本(与用于启动Maven的版本不同)来编译代码,请参阅使用其他JDK进行编译的示例。”
See: https://maven.apache.org/plugins/maven-compiler-plugin/examples/set-compiler-source-and-target.html 参见: https : //maven.apache.org/plugins/maven-compiler-plugin/examples/set-compiler-source-and-target.html
In other words: if you want to make sure your project is using the correct Java version and thus correct JAXB version, use the Animal Sniffer Maven Plugin. 换句话说:如果要确保项目使用的是正确的Java版本,从而是正确的JAXB版本,请使用Animal Sniffer Maven插件。 See: http://www.mojohaus.org/animal-sniffer/animal-sniffer-maven-plugin/
请参阅: http : //www.mojohaus.org/animal-sniffer/animal-sniffer-maven-plugin/
That's all ;) 就这样 ;)
JAXB seems only support xml simple
type only in <xjc:javaType>
and hence you are seeing error " ...unable to honor...
". JAXB似乎仅在
<xjc:javaType>
仅支持xml simple
类型,因此您将看到错误“ ...unable to honor...
”。 See related question on this. 参见相关问题 。
How to generate @XmlJavaTypeAdapter
annotation on generted class. 如何在生成的类上生成
@XmlJavaTypeAdapter
批注。 (based on jaxb2-annotate-plugin ) (基于jaxb2-annotate-plugin )
Specify @XmlJavaTypeAdapter in binding file as shown below 在绑定文件中指定@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>
Configure the JAXB plugin in your pom file as: 将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>
You have a class name conflict between your two Locale
classes. 您的两个
Locale
类之间的类名冲突。
I got your code working by making the following changes. 通过进行以下更改,我使您的代码正常工作。 I didn't generate the JAXB classes from the XML schema, but simply updated them directly, so you'll have to figure out how to update the bindings file to get this result.
我不是从XML模式生成JAXB类,而是直接直接对其进行更新,因此您必须弄清楚如何更新绑定文件才能获得此结果。
Rename your Locale
class, so it doesn't conflict with java.util.Locale
, eg rename to LocaleType
. 重命名您的
Locale
类,因此它与java.util.Locale
不冲突,例如,重命名为LocaleType
。
Change org.mylib.schema.Locale
to org.mylib.schema.LocaleType
in LocaleXmlAdapter
. 更改
org.mylib.schema.Locale
到org.mylib.schema.LocaleType
在LocaleXmlAdapter
。
Note: You can now use import statements and not have to fully qualify the classes in the code. 注意:现在,您可以使用import语句,而不必完全限定代码中的类。
Make sure DelimitedDataSchema
uses java.util.Locale
, eg it still says Locale
in the field and method declarations, and it imports java.util.Locale
. 确保
DelimitedDataSchema
使用java.util.Locale
,例如,它在字段和方法声明中仍显示Locale
,并导入java.util.Locale
。
Add @XmlJavaTypeAdapter(LocaleXmlAdapter.class)
to the locale
field of DelimitedDataSchema
. 将
@XmlJavaTypeAdapter(LocaleXmlAdapter.class)
添加到DelimitedDataSchema
的locale
字段中。
Now it works. 现在可以了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.