maven-jaxb2-plugin在同一个项目中重用公共XSD [英] maven-jaxb2-plugin reusing commons XSD within same project
问题描述
我有一个项目,它有一个模式A和B,都在同一个命名空间内。两个导入模式C也使用相同的命名空间。如何为A和B生成JAXB类以分离包,同时重用从生成的C到公共包的JAXB类?
I have a project which has a schema A and B, both within the same namespace. Both import schema C which also uses the same namespace. How can I generate JAXB classes for A and B to separate packages, while reusing the JAXB classes from C generated to a commons package?
我已经知道我应该使用它剧集并使用为模式C生成的剧集作为模式A和B的单独执行的绑定文件。问题是我不知道如何引用这个生成的剧集文件。
I already know I should probably be using episodes and use the episode generated for schema C as bindings file for the separate executions of schema's A and B. Problem is I don't know how to refer to this generated episode file.
以下是一个示例:
<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>
这会导致在以下位置创建剧集文件:
This causes an episode file to be created under:
target/generated-sources/xjc-commons/META-INF/sun-jaxb.episode
如何在A和B的执行中引用此剧集/绑定文件? 使用剧集仅提及如何从中引用剧集文件其他jar依赖项(或者我根本不理解它,更有可能)。
How do I refer to this episode/bindings file in executions for A and B? Using Episodes only mentions how to refer to an episode file from other jar dependencies (or I simply didn't understand it properly, which is more likely).
我看到一个较旧的答案建议将它作为参数 -b
传递给XJC,但这似乎没有做任何事情为了我。我最终还是从C生成了三次相同的类。
I've seen an older answer suggest to pass it as a parameter -b
to XJC, but that didn't seem to do anything for me. I still end up with the same class from C generated three times.
推荐答案
免责声明:我是 maven-jaxb2-插件。
TL; DR这里是测试项目,演示如何执行此操作。
TL;DR here's a test project which demonstrates how to do this.
这是可能的,但有点毛茸茸,所以请耐心等待。
This is possible, but is a bit hairy, so please bear with me.
如果 a.xsd
, b.xsd
和 c.xsd
位于同一名称空间中, a.xsd
和 b.xsd
无法导入 c.xsd
,他们只能包含它。我们想要将每个XSD生成到它自己的包中,例如 test.a
, test.b
和 test.c
并在同一个Maven项目中进行。
If a.xsd
, b.xsd
and c.xsd
are in the same namespace, a.xsd
and b.xsd
cannot import c.xsd
, they can only include it. We want to generate each of the XSDs into its own package, say test.a
, test.b
and test.c
and do it within the same single Maven project.
为此,我们需要三次单独执行 maven-jaxb2-plugin
,每个都配置了自己的架构和目标包。例如:
To do this we will need three separate executions of the maven-jaxb2-plugin
, each configured with its own schema and target package. For example:
<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>
好的,这将创建三个具有三个目标包的目标目录。下一个问题是 c.xsd
中的类将在 test.a
和测试中生成。 b
我们要避免这种情况。
OK, this would create three target directories with three target packages. Next problem is that classes from c.xsd
will generated in test.a
and test.b
which we want to avoid.
为实现这一目标,我们必须告诉XJC使用 test中的类。 c
表示来自 c.xsd
的类型。这实际上是剧集文件的用途。此文件通常在 META-INF \sun-jaxb.episode
下生成,它包含已处理模式中所有类型的绑定。以下是为生成的示例c.xsd
:
To achieve this, we have to tell XJC to use classes from test.c
for types from c.xsd
. This is actually what episode file is for. This file is normally generated under META-INF\sun-jaxb.episode
and it contains bindings for all types in the processed schema. Here's an example generated for 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>
剧集文件实际上是正常的绑定文件。所以你可以直接在编译中使用它:
Episode file is actually a normal bindings file. So you can directly use it in compilation:
<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生成的剧集文件也包含此片段:
There is just one tiny problem left. Episode files generated by XJC also contain this fragment:
<schemaBindings map="false">
<!-- ... -->
</schemaBindings>
它实际上说执行不为给定命名空间中的模式生成代码。如果 a.xsd
或 b.xsd
将位于不同的命名空间中,这将不会成为问题。但由于它们位于相同的命名空间中,因此该片段将有效地关闭 a.xsd
或 b.xsd $ c $的所有代码生成c>。
It effectively says "do not generate code for schema in the given namespace". This would not be a problem if a.xsd
or b.xsd
would be in a different namespace. But since they are in the same namespace, this fragment will effectively turn off all code generation for a.xsd
or b.xsd
.
要解决此问题,我们可以对为生成的 sun-jaxb.episode
进行后处理 c.xsd
。这可以通过一个简单的XSLT完成:
To work around this we can post-process the sun-jaxb.episode
which was generated for c.xsd
. This can be done with a simple 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 $的代码后运行c $ c>,但在生成
a.xsd
和 b.xsd
的代码之前。这可以通过将这些执行分为不同的阶段来实现( generate-sources
, process-sources
, generate-resources
)。
This XSLT should be run after the code for c.xsd
, but before the code for a.xsd
and b.xsd
is generated. This can be achieved by putting these executions into different phases (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>
这篇关于maven-jaxb2-plugin在同一个项目中重用公共XSD的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!