maven-jaxb2-plugin 在同一项目中重用公共资源 XSD

maven-jaxb2-plugin reusing commons XSD within same project

我有一个项目,它有架构 A 和 B,它们都在同一个命名空间中。两者都导入也使用相同名称空间的模式 C。如何为 A 和 B 生成 JAXB classes 以分隔包,同时重用 C 生成的 JAXB classes 到公共包?

我已经知道我可能应该使用剧集并将为模式 C 生成的剧集用作模式 A 和 B 的单独执行的绑定文件。问题是我不知道如何引用这个生成的剧集文件.

这是一个例子:

<plugin>
    <groupId>org.jvnet.jaxb2.maven2</groupId>
    <artifactId>maven-jaxb2-plugin</artifactId>
    <version>0.12.3</version>
    <executions>
        <execution>
            <id>generate-sources-C</id>
            <goals>
                <goal>generate</goal>
            </goals>
            <configuration>
                <generatePackage>com.mymodel.commons</generatePackage>
                <generateDirectory>${project.build.directory}/generated-sources/xjc-commons</generateDirectory>
                <schemas>
                    <schema><url>src/main/resources/xsd/mymodel/c.xsd</url></schema>
                </schemas>
            </configuration>
        </execution>
        <execution>
            <id>generate-sources-A</id>
            <goals>
                <goal>generate</goal>
            </goals>
            <configuration>
                <generatePackage>com.mymodel.a</generatePackage>
                <schemas>
                    <schema><url>src/main/resources/xsd/mymodel/a.xsd</url></schema>
                </schemas>
            </configuration>
        </execution>
        <execution>
            <id>generate-sources-B</id>
            <goals>
                <goal>generate</goal>
            </goals>
            <configuration>
                <generatePackage>com.mymodel.b</generatePackage>
                <schemas>
                    <schema><url>src/main/resources/xsd/mymodel/b.xsd</url></schema>
                </schemas>
            </configuration>
        </execution>
    </executions>
</plugin>

这会导致在以下位置创建剧集文件:

target/generated-sources/xjc-commons/META-INF/sun-jaxb.episode

如何在 A 和 B 的执行中引用此 episode/bindings 文件? Using Episodes 只提到了如何从其他jar 依赖中引用一个episode 文件(或者我根本没有正确理解它,这更有可能)。

我看到一个较旧的答案建议 pass it as a parameter -b 给 XJC,但这似乎对我没有任何作用。我仍然从 C 生成了三次相同的 class。

免责声明:我是的作者。

TL;DR 这里有一个 test project 演示了如何做到这一点。

这个是可以的,但是有点啰嗦,还请多多包涵。

如果a.xsdb.xsdc.xsd在同一个命名空间中,a.xsdb.xsd不能导入 c.xsd,他们只能包含它。我们想将每个 XSD 生成到自己的包中,比如 test.atest.btest.c,并在同一个 Maven 项目中完成。

为此,我们需要三个单独的 maven-jaxb2-plugin 执行,每个执行都配置了自己的模式和目标包。例如:

        <plugin>
            <groupId>org.jvnet.jaxb2.maven2</groupId>
            <artifactId>maven-jaxb2-plugin</artifactId>
            <executions>
                <execution>
                    <id>xjc-a</id>
                    <goals>
                        <goal>generate</goal>
                    </goals>
                    <configuration>
                        <generatePackage>test.a</generatePackage>
                        <generateDirectory>${project.build.directory}/xjc-a</generateDirectory>
                        <schemaIncludes>
                            <includes>a.xsd</includes>
                        </schemaIncludes>
                    </configuration>
                </execution>
                <!-- xjc-b and xjc-c follow -->
            </executions>
        </plugin>

It is is important to use different target directories for separate executions.

好的,这将创建三个包含三个目标包的目标目录。下一个问题是 c.xsd 中的 类 将在 test.atest.b 中生成,这是我们要避免的。

为了实现这一点,我们必须告诉 XJC 使用 test.c 中的 类 作为 c.xsd 中的类型。这实际上就是 episode 文件的用途。此文件通常在 META-INF\sun-jaxb.episode 下生成,它包含已处理架构中所有类型的绑定。这是为 c.xsd:

生成的示例
<?xml version="1.0" encoding="UTF-8"?>
<bindings xmlns="http://java.sun.com/xml/ns/jaxb" if-exists="true" version="2.1">
  <bindings xmlns:tns="urn:test" if-exists="true" scd="x-schema::tns">
    <schemaBindings map="false">
      <package name="test.c"/>
    </schemaBindings>
    <bindings if-exists="true" scd="~tns:CType">
      <class ref="test.c.CType"/>
    </bindings>
  </bindings>
</bindings>

剧集文件实际上是一个普通的绑定文件。所以可以直接编译使用:

                <execution>
                    <id>xjc-a</id>
                    <goals>
                        <goal>generate</goal>
                    </goals>
                    <configuration>
                        <generatePackage>test.a</generatePackage>
                        <generateDirectory>${project.build.directory}/xjc-a</generateDirectory>
                        <schemaIncludes>
                            <includes>a.xsd</includes>
                        </schemaIncludes>
                        <bindings>
                            <binding>
                                <fileset>
                                    <directory>${project.build.directory}/xjc-c/META-INF</directory>
                                    <includes>
                                        <include>sun-jaxb.episode</include>
                                    </includes>
                                </fileset>
                            </binding>
                        </bindings>
                    </configuration>
                </execution>

只剩下一个小问题了。 XJC 生成的剧集文件也包含这个片段:

    <schemaBindings map="false">
      <!-- ... -->
    </schemaBindings>

它实际上表示 "do not generate code for schema in the given namespace"。如果 a.xsdb.xsd 位于不同的命名空间中,这将不是问题。但由于它们在同一个命名空间中,因此该片段将有效地关闭 a.xsdb.xsd.

的所有代码生成

要解决这个问题,我们可以 post 处理为 c.xsd 生成的 sun-jaxb.episode。这可以通过一个简单的 XSLT 来完成:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" version="1.0">
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>
    <xsl:template match="jaxb:schemaBindings"/>
</xsl:stylesheet>

此 XSLT 应 运行 在 c.xsd 的代码之后,但在生成 a.xsdb.xsd 的代码之前。这可以通过将这些执行分为不同的阶段来实现(generate-sourcesprocess-sourcesgenerate-resources)。


下面是完整的pom.xml:

<?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.jvnet.jaxb2.maven2</groupId>
    <artifactId>divide</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.glassfish.jaxb</groupId>
            <artifactId>jaxb-runtime</artifactId>
            <version>2.2.11</version>
        </dependency>
        <!-- JUnit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
            <version>4.12</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>xml-maven-plugin</artifactId>
                <version>1.0.2</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>transform</goal>
                        </goals>
                        <phase>process-sources</phase>
                    </execution>
                </executions>
                <configuration>
                    <transformationSets>
                        <transformationSet>
                            <dir>${project.build.directory}/xjc-c/META-INF</dir>
                            <outputDir>${project.build.directory}/xjc-c/META-INF</outputDir>
                            <includes>
                                <include>sun-jaxb.episode</include>
                            </includes>
                            <stylesheet>src/main/xslt/removeJaxbSchemaBindings.xslt</stylesheet>
                        </transformationSet>
                    </transformationSets>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.jvnet.jaxb2.maven2</groupId>
                <artifactId>maven-jaxb2-plugin</artifactId>
                <version>0.13.3</version>
                <executions>
                    <execution>
                        <id>xjc-c</id>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                        <phase>generate-sources</phase>
                        <configuration>
                            <generatePackage>test.c</generatePackage>
                            <generateDirectory>${project.build.directory}/xjc-c</generateDirectory>
                            <schemaIncludes>
                                <includes>c.xsd</includes>
                            </schemaIncludes>
                        </configuration>
                    </execution>
                    <execution>
                        <id>xjc-a</id>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                        <phase>generate-resources</phase>
                        <configuration>
                            <generatePackage>test.a</generatePackage>
                            <generateDirectory>${project.build.directory}/xjc-a</generateDirectory>
                            <schemaIncludes>
                                <includes>a.xsd</includes>
                            </schemaIncludes>
                            <bindings>
                                <binding>
                                    <fileset>
                                        <directory>${project.build.directory}/xjc-c/META-INF</directory>
                                        <includes>
                                            <include>sun-jaxb.episode</include>
                                        </includes>
                                    </fileset>
                                </binding>
                            </bindings>
                        </configuration>
                    </execution>
                    <execution>
                        <id>xjc-b</id>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                        <phase>generate-resources</phase>
                        <configuration>
                            <generatePackage>test.b</generatePackage>
                            <generateDirectory>${project.build.directory}/xjc-b</generateDirectory>
                            <schemaIncludes>
                                <includes>b.xsd</includes>
                            </schemaIncludes>
                            <bindings>
                                <binding>
                                    <fileset>
                                        <directory>${project.build.directory}/xjc-c/META-INF</directory>
                                        <includes>
                                            <include>sun-jaxb.episode</include>
                                        </includes>
                                    </fileset>
                                </binding>
                            </bindings>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>