我怀疑对此没有好的答案,但希望我遗漏了一些东西。假设我有两个独立的 XML 模式,它们都具有相同的命名空间,定义了一些重复的复杂类型,并且我想使用 JAXB 为它们生成 Java 类。作为一个非常简单的例子:
schema1.xsd:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema elementFormDefault="qualified" targetNamespace="namespace1" xmlns="namespace1" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="foo" type="xs:string"/>
</xs:schema>
和
schema2.xsd:(与上面相同)
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema elementFormDefault="qualified" targetNamespace="namespace1" xmlns="namespace1" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="foo" type="xs:string"/>
</xs:schema>
当我尝试使用 JAXB(通过 gradle 的 Ant XJC 任务)生成这些内容时,我收到以下完全合理的错误:
[ant:xjc] [ERROR] 'foo' is already defined
[ant:xjc] line 3 of file:/C:/dev/test/src/main/resources/schema2.xsd
[ant:xjc]
[ant:xjc] [ERROR] (related to above error) the first definition appears here
[ant:xjc] line 3 of file:/C:/dev/test/src/main/resources/schema1.xsd
根据 JAXB 文档,我尝试在外部自定义文件中指定包,如下所示:
<jaxb:bindings schemaLocation="schema1.xsd">
<jaxb:schemaBindings>
<jaxb:package name="package1"/>
</jaxb:schemaBindings>
</jaxb:bindings>
<jaxb:bindings schemaLocation="schema2.xsd">
<jaxb:schemaBindings>
<jaxb:package name="package2"/>
</jaxb:schemaBindings>
</jaxb:bindings>
但这不起作用 - 然后我意识到上面链接的相同文档说:
请注意,此自定义是针对每个命名空间的。也就是说,即使您的架构被拆分为多个架构文档,如果它们都位于同一命名空间中,您也不能将它们放入不同的包中。
所以,我猜这永远不会起作用。
有什么明智的方法吗?我怀疑正确的答案是模式应该位于不同的命名空间中,因为这可以解决问题,并且可能更具逻辑意义,但我对模式没有任何控制权 - 它们是由第三方提供的。我问过是否可以更改它们,但我怀疑答案是否定的。
我能看到的唯一其他选项是生成 Java 类两次,首先为 schema1.xsd,然后单独为 schema2.xsd,每次都使用自己的自定义文件指定不同的包,但这感觉像是一个非常笨拙的解决方案。我还缺少更明智的选择吗?
你不能。包是根据命名空间生成的。相同的命名空间 - 相同的包。
在这种情况下你必须执行多次。还要注意使用不同的输出生成目录(如
target/generated-sources/xjc1
、target/generated-sources/xjc2
),否则“仅在发生任何更改时才编译”将无法正常工作。
lexcore 是对的,如果你想从同一个 XML 命名空间为不同的 Java 包生成类,你必须使用多次执行。
您可能会在
schema1.xsd
和 schema2.xsd
中使用相同的 XML 类型,例如,将一些 common.xsd
包含到 schema1.xsd
和 schema2.xsd
中。如果您只运行两次执行,您将在 package1
和 package2
中重复这些常见类型。
您可以使用以下方法避免此类重复。
该方法已通过
maven-jaxb-plugin
版本3.1.0
进行测试。
你必须制作4个XJB文件:
common.xjb
和 common-classes.xjb
为常见类型schema1.xjb
适用于 schema1.xsd
schema2.xjb
适用于 schema2.xsd
common.xjb
将常用类型放入 common
Java 包中:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<bindings version="3.0" xmlns="https://jakarta.ee/xml/ns/jaxb">
<bindings scd="x-schema::tns" xmlns:tns="https://namespace1">
<schemaBindings>
<package name="common"/>
</schemaBindings>
</bindings>
</bindings>
common-classes.xjb
将指示 schema1
和 schema2
重用 common
Java 包中的常见类型:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<bindings version="3.0" xmlns="https://jakarta.ee/xml/ns/jaxb">
<bindings scd="x-schema::tns" xmlns:tns="https://namespace1">
<bindings scd="~tns:CommonType1">
<class ref="common.CommonType1"/>
</bindings>
<bindings scd="~tns:CommonType2">
<class ref="common.CommonType2"/>
</bindings>
<!-- ... -->
</bindings>
</bindings>
请注意,
maven-jaxb-plugin
可以通过在 common-classes.xjb
上执行来为您生成大部分 common.xsd
文件。执行后查看target/classes/META-INF/JAXB
目录。
schema1.xjb
会将 schema1.xsd
特定类型放入 package1
:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<bindings version="3.0" xmlns="https://jakarta.ee/xml/ns/jaxb">
<bindings scd="x-schema::tns" xmlns:tns="https://namespace1">
<schemaBindings>
<package name="package1"/>
</schemaBindings>
</bindings>
</bindings>
schema2.xjb
会将 schema2.xsd
特定类型放入 package2
:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<bindings version="3.0" xmlns="https://jakarta.ee/xml/ns/jaxb">
<bindings scd="x-schema::tns" xmlns:tns="https://namespace1">
<schemaBindings>
<package name="package2"/>
</schemaBindings>
</bindings>
</bindings>
最后,您必须在
maven-jaxb-plugin
中定义 3 个 pom.xml
执行:
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>3.1.0</version>
<!-- Common configuration for all executions -->
<configuration>
<clearOutputDir>false</clearOutputDir>
</configuration>
<executions>
<execution>
<id>xjc-common</id>
<goals>
<goal>xjc</goal>
</goals>
<configuration>
<sources>
<source>common.xsd</source>
</sources>
<xjbSources>
<xjbSource>common.xjb</xjbSource>
</xjbSources>
</configuration>
</execution>
<execution>
<id>xjc-schema1</id>
<goals>
<goal>xjc</goal>
</goals>
<configuration>
<sources>
<source>schema1.xsd</source>
</sources>
<xjbSources>
<xjbSource>common-classes.xjb</xjbSource>
<xjbSource>schema1.xjb</xjbSource>
</xjbSources>
</configuration>
</execution>
<execution>
<id>xjc-schema2</id>
<goals>
<goal>xjc</goal>
</goals>
<configuration>
<sources>
<source>schema2.xsd</source>
</sources>
<xjbSources>
<xjbSource>common-classes.xjb</xjbSource>
<xjbSource>schema2.xjb</xjbSource>
</xjbSources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>