我使用 JAXB 获得了此 API,以便通过命名引用方便地使用由 XJC(XML 到 Java)编译器从 XML 模式生成的对象模型。它通过各种背景魔法和反射抽象了 JAXB 上下文的创建和查找 ObjectFactory 方法。其基本要点是,您始终定义一个通用模式,然后定义任意数量(也可能是 0)的模式“扩展”该通用模式,每个模式都会产生自己的数据模型。通用模式带有可重用的定义,扩展它的定义使用这些定义来组成自己的模型。
我现在遇到了一种情况,我想为多个项目重用通用模式。通用类型定义在项目中应该保持相同,并且一些代码将根据这些代码生成的抽象类构建。因此,我需要首先为某些通用模式生成类,然后生成那些扩展并单独使用它们的类。我在构建过程中使用 Maven。
我遇到的问题是从扩展模式中的通用模式解析类型定义。
假设我的通用架构名为“general.xsd”,如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.foobar.com/general"
xmlns:gen="http://www.foobar.com/general"
elementFormDefault="qualified" attributeFormDefault="qualified">
<!-- Element (will usually be root) -->
<xs:element name="transmission" type="gen:Transmission" />
<!-- Definition -->
<xs:complexType name="Transmission" abstract="true">
<xs:sequence>
<!-- Generic parts of a transmission would be in here... -->
</xs:sequence>
</xs:complexType>
</xs:schema>
旁边有一个绑定文件,用于进行一些命名自定义并设置输出的包名称:
<?xml version="1.0" encoding="UTF-8"?>
<bindings xmlns="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
version="2.1">
<!-- Bindings for the general schema -->
<bindings schemaLocation="general.xsd" node="/xs:schema">
<schemaBindings>
<package name="com.foobar.models.general"/>
</schemaBindings>
<bindings node="//xs:complexType[@name='Transmission']">
<!-- Some customization of property names here... -->
</bindings>
</bindings>
然后,我将在该项目的 POM 中添加下一部分来生成 Java 类:
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb21-plugin</artifactId>
<version>0.8.0</version>
<executions>
<execution>
<id>xjc-generate</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<schemaDirectory>${basedir}/src/main/resources/com/foobar/schemas</schemaDirectory>
<schemaLanguage>XMLSCHEMA</schemaLanguage>
<addCompileSourceRoot>true</addCompileSourceRoot>
<episode>true</episode>
<removeOldOutput>true</removeOldOutput>
</configuration>
</execution>
</executions>
</plugin>
如您所见,我正在使用 JAXB2.1 Maven 插件。我已设置选项来生成用于逐步编译的剧集文件。删除以前的输出的选项是为了解决错误;它所做的只是确保首先清理所有内容,以便强制重新编译。
到目前为止,一切都很好。该项目编译顺利。应该注意的是,除了生成的 Java 类之外,我还将模式打包到生成的 jar 文件中。所以这些在类路径上可用!这sun-jaxb.episode
文件应该在 META-INF 中。
然后我开始使用模式的项目,该模式将扩展上述内容,首先导入它。其中一种“子类型”可能如下所示(我将其称为 sub.xsd):
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.foobar.com/sub"
xmlns:sub="http://www.foobar.com/sub"
xmlns:gen="http://www.foobar.com/general"
elementFormDefault="qualified" attributeFormDefault="qualified">
<xs:import namespace="http://www.foobar.com/general" />
<!-- Definition -->
<xs:complexType name="SubTransmission">
<xs:complexContent>
<xs:extension base="gen:Transmission">
<xs:sequence>
<!-- Additional elements placed here... -->
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
同样,有一个绑定文件:
<?xml version="1.0" encoding="UTF-8"?>
<bindings xmlns="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
version="2.1">
<!-- Bindings for sub type -->
<bindings schemaLocation="sub.xsd" node="/xs:schema">
<schemaBindings>
<package name="com.foobar.models.sub"/>
</schemaBindings>
</bindings>
</bindings>
以下是该项目 POM 中负责 XJC 生成的部分内容:
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb21-plugin</artifactId>
<version>0.8.0</version>
<executions>
<execution>
<id>xjc-generate</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<schemaDirectory>${basedir}/src/main/resources/com/foobar/schemas</schemaDirectory>
<schemaLanguage>XMLSCHEMA</schemaLanguage>
<addCompileSourceRoot>true</addCompileSourceRoot>
<episode>false</episode>
<catalog>${basedir}/src/main/resources/com/foobar/schemas/catalog.cat</catalog>
<episodes>
<episode>
<groupId>com.foobar</groupId>
<artifactId>foobar-general-models</artifactId>
<version>1.0.0-SNAPSHOT</version>
<scope>compile</scope>
</episode>
</episodes>
<removeOldOutput>true</removeOldOutput>
</configuration>
</execution>
</executions>
</plugin>
最初,所有模式都在一个文件夹中,我有schemaLocation
导入中的属性设置为general.xsd
,效果很好。但现在事情是跨项目分开的,我遇到了问题。第一个问题是找不到其他架构。我已经解决了这个问题schemaLocation
属性出自<xs:import />
元素,只保留namespace
属性并添加目录文件(catalog.cat
)您可以在上面的 POM 摘录中看到引用。其内容是:
PUBLIC "http://www.foobar.com/general" "classpath:/com/foobar/schemas/general.xsd"
这似乎有效,因为我不再收到指出找不到架构的错误。但由于某种原因,从导入的架构解析实际类型定义仍然失败。这是例外情况:
Error while parsing schema(s).Location [ file:/C:/NetBeans_groups/Test/SubModelBundle/src/main/resources/com/foobar/schemas/sub.xsd{...,...}].
org.xml.sax.SAXParseException: src-resolve: Cannot resolve the name 'gen:Transmission' to a(n) 'type definition' component.
到目前为止,这是我尝试过的:
- 使用目录文件。部分成功,因为现在可以找到导入的架构。
- 让通用模式的编译生成一个情节文件,并将其用于子模式的编译。似乎没有什么区别,尽管这应该只在类型解析后发挥作用,所以我认为这还不重要。
- 使用不同的 JAXP(注意:notJAXB、JAXP) 实现。它确实使用了不同的,因为我可以在异常的堆栈跟踪中看到这一点,但最终结果是相同的。
- Use the
maven-jaxb22-plugin
而不是 21。没有区别。
在网上查了一下,似乎人们至少从 2006 年就开始遇到这个问题,它可能与一些 Xerces 解析器问题有关。我希望这不是一个已经潜伏了 6 年而没有人关心修复的错误。其他人有一些建议吗?也许有人遇到了同样的问题并找到了解决方案?我能想到的唯一解决方法是使用“svn:externals”将通用模式拖到子项目中,然后在那里重新生成类,但它很脏,并且只有当您可以连接到我们的 svn 存储库时才有效。
非常感谢您阅读这篇长文章。请记住,我已经从现有项目中获取了上述所有内容,并为了匿名而替换了一些名称空间和其他内容,因此可能存在一些拼写错误。