【问题标题】:maven-jaxb2-plugin reusing commons XSD within same projectmaven-jaxb2-plugin 在同一项目中重用公共 XSD
【发布时间】:2018-05-04 13:27:56
【问题描述】:

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

我已经知道我可能应该使用剧集并将为模式 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 的执行中引用此情节/绑定文件? Using Episodes 只提到了如何从其他 jar 依赖项中引用剧集文件(或者我根本没有正确理解它,这更有可能)。

我已经看到向 XJC 建议 pass it as a parameter -b 的较旧答案,但这似乎对我没有任何帮助。我仍然会从 C 中生成相同的类 3 次。

【问题讨论】:

    标签: java maven jaxb xjc maven-jaxb2-plugin


    【解决方案1】:

    免责声明:我是的作者。

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

    这是可能的,但有点毛,所以请多多包涵。

    如果a.xsd、b.xsd和c.xsd在同一个命名空间,a.xsd和b.xsd不能导入c.xsd,只能包含时间>它。我们希望将每个 XSD 生成到自己的包中,例如 test.a、test.b 和 test.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.a 和test.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>
    

    它实际上是说“不要不为给定命名空间中的模式生成代码”。如果a.xsd 或b.xsd 位于不同的命名空间中,这将不是问题。但由于它们在同一个命名空间中,因此该片段将有效地关闭 a.xsd 或 b.xsd 的所有代码生成。

    要解决这个问题,我们可以对为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.xsd 和 b.xsd 的代码生成之前运行。这可以通过将这些执行放入不同的阶段来实现(generate-sources、process-sources、generate-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>
    

    【讨论】:

    • 我没想到会这样。我想我正在尝试做一些非常规的事情。非常感谢您对此进行调查。考虑到 XSLT 步骤,我想您也必须尝试一下:D
    • @BennyBottema 它是非传统的。常规是一个命名空间 - 一个包。你想要一个命名空间——三个包。 如果 c.xsd 有自己的命名空间,它会容易得多(没有 XSLT)。
    • 是的,我也这么想。不幸的是,我正在处理一套遗留系统的限制,这些系统被锁定在这个包模式中。再次,非常感谢你清理这个!
    • 如果入口模式是导入相应 XSD 的 WSDL,这显然不起作用。如果我直接引用 XSD,则此设置有效。我不确定我是否需要这里的 WSDL,但有没有办法解决这个问题?
    • @BennyBottema 我对 WSDL 没有太多经验。可能是的,绑定+目录有很大的威力,但如果不尝试就很难说。
    猜你喜欢
    • 1970-01-01
    • 2015-09-20
    • 2013-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-21
    相关资源
    最近更新 更多