编辑:由于要求是通用解决方案,且不使用外部绑定文件,因此我提供了下面的两个选项:
选项1 - 通用解决方案 - 创建自定义XJC插件进行规范化
通用解决方案实际上是:
- 扩展
com.sun.tools.xjc.Plugin
抽象类并覆盖JAXB
用于命名工件的方法 - 基本上创建一个插件
- 在
jar
中打包此实现,并在META-INF
文件夹内的services
目录中明确调用实现的名称
- 将这个新创建的
jar
与jaxb
库一起部署,并通过ANT运行它(下面提供了build.xml
,请继续阅读)
为了你的目的,我创建了一个插件,你可以从这里下载jar包,从这里下载ant脚本 (build.xml
)。将jar包放入eclipse的构建路径中,并编辑ant文件以提供你的JAXB库位置、生成类的目标包、项目名称和模式位置,然后运行它。就是这样!
XJC
具有创建自定义插件的功能,以控制生成的类、变量等的名称、注释和其他属性。 这篇博客文章虽然有些旧,但可以让您入门了解此类插件实现的基础知识。
长话短说,我创建了一个扩展抽象com.sun.tools.xjc.Plugin
类的类,重写其重要方法之一 onActivated
。
在此方法中,我设置了 com.sun.tools.xjc.Option#setNameConverter
为一个自定义类,该类负责覆盖获取类名、方法名等所需方法。 我还将源代码提交到了我的git repo here,以下是详细用法:
import java.text.Normalizer;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import com.sun.tools.xjc.BadCommandLineException;
import com.sun.tools.xjc.Options;
import com.sun.tools.xjc.Plugin;
import com.sun.tools.xjc.outline.Outline;
import com.sun.xml.bind.api.impl.NameConverter;
public class NormalizeElements extends Plugin {
@Override
public String getOptionName() {
return "normalize";
}
@Override
public String getUsage() {
return " -normalize : normalize the classes and method names generated by removing the accented characters";
}
@Override
public void onActivated(Options opts) throws BadCommandLineException {
opts.setNameConverter(new NonAsciiConverter(), this);
}
@Override
public boolean run(Outline model, Options opt, ErrorHandler errorHandler)
throws SAXException {
return true;
}
}
class NonAsciiConverter extends NameConverter.Standard {
@Override
public String toClassName(String s) {
String origStr = super.toClassName(s);
return normalize(origStr);
}
@Override
public String toPropertyName(String s) {
String origStr = super.toPropertyName(s);
return normalize(origStr);
}
@Override
public String toVariableName(String s) {
String origStr = super.toVariableName(s);
return normalize(origStr);
}
@Override
public String toInterfaceName(String s) {
String origStr = super.toInterfaceName(s);
return normalize(origStr);
}
private String normalize(String accented) {
String normalized = Normalizer.normalize(accented, Normalizer.Form.NFD);
normalized = normalized.replaceAll("[^\\p{ASCII}]", "");
return normalized;
}
}
要使用普通的
jaxb
反序列化启用此插件,需要将这些类打包到一个 jar 文件中,在该 jar 文件中添加
/META-INF/services/com.sun.tools.xjc.Plugin
文件,并将其放置在构建路径中。
在 jar 文件中添加
/META-INF/services/com.sun.tools.xjc.Plugin
文件。
这个文件读取:
com.popofibo.plugins.jaxb.NormalizeElements
如前所述,我将其打包成jar
文件,并在我的eclipse构建路径中进行部署。现在我在运行eclipse kepler with JDK 1.7
时遇到的问题是我收到了这个异常(消息):
com.sun.tools.xjc.plugin Provider <my class> not a subtype
因此,最好使用ANT生成类,以下的
build.xml
对到目前为止所做的工作做了很好的处理:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<project name="SomeProject" default="createClasses">
<taskdef name="xjc" classname="com.sun.tools.xjc.XJC2Task">
<classpath>
<pathelement
path="C:/Workspace/jaxb-ri-2.2.7/jaxb-ri-2.2.7/lib/jaxb-xjc.jar" />
<pathelement
path="C:/Workspace/jaxb-ri-2.2.7/jaxb-ri-2.2.7/lib/jaxb-impl.jar" />
<pathelement
path="C:/Workspace/jaxb-ri-2.2.7/jaxb-ri-2.2.7/lib/jaxb2-value-constructor.jar" />
<pathelement path="C:/Workspace/normalizeplugin_xjc_v0.4.jar" />
</classpath>
</taskdef>
<target name="clean">
<delete dir="src/com/popofibo/jaxb" />
</target>
<target name="createClasses" depends="clean">
<xjc schema="res/some.xsd" destdir="src" package="com.popofibo.jaxb"
encoding="UTF-8">
<arg value="-normalize" />
</xjc>
</target>
</project>
我选择展示这个规范化过程的模式是:
<xs:element name="shiporder">
<xs:complexType>
<xs:sequence>
<xs:element name="Örderperson" type="xs:string"/>
<xs:element name="Şhİpto">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="address" type="xs:string"/>
<xs:element name="Çity" type="xs:string"/>
<xs:element name="ÇoÜntry" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="İtem" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="title" type="xs:string"/>
<xs:element name="note" type="xs:string" minOccurs="0"/>
<xs:element name="qÜantity" type="xs:positiveInteger"/>
<xs:element name="price" type="xs:decimal"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="orderid" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
</xs:schema>
正如您所看到的,我已经设置了参数和包,以便在其中生成我的类 - 生成的工件中的类、方法、变量的ASCII名称(我唯一看到的差距是XML注释,这不会影响原因,但也很容易克服)。
上面的截图显示名称已被规范化并替换为它们的ASCII对应项(如需查看未替换内容的外观,请参见选项2中的屏幕截图)。
选项2 - 使用外部绑定文件
要删除重音字符,您可以创建自定义绑定文件,并在生成类时使用它来绑定您的类和属性名称。请参阅:
使用JAXB绑定声明创建外部绑定声明文件
我使用了在选项1中已提到的xsd,其中包含“带重音”的元素名称(非ASCII字符):
如果我在不指定外部绑定的情况下生成类,我将得到以下输出:
!
现在,如果我稍微更改绑定来生成我选择的类名和变量,我会将我的
binding.xml
编写为:
<jxb:bindings xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb" version="2.1">
<jxb:globalBindings localScoping="toplevel" />
<jxb:bindings schemaLocation="some.xsd">
<jxb:bindings node="//xs:element[@name='Şhİpto']">
<jxb:class name="ShipTo" />
</jxb:bindings>
<jxb:bindings node="//xs:element[@name='Örderperson']">
<jxb:property name="OrderPerson" />
</jxb:bindings>
<jxb:bindings node="//xs:element[@name='Şhİpto']//xs:complexType">
<jxb:class name="ShipToo" />
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>
现在,当我通过指定绑定文件在 Eclipse 中生成我的类时:
在接下来的步骤中,我会选择包和绑定文件。
注意:如果您没有使用 Eclipse 生成您的类,则可能需要检查
xjc binding compiler 以利用您的外部绑定文件。