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?
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.
Here's an example:
<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
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).
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.
Disclaimer: I am the author of maven-jaxb2-plugin.
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.
If
a.xsd
,b.xsd
andc.xsd
are in the same namespace,a.xsd
andb.xsd
cannot importc.xsd
, they can only include it. We want to generate each of the XSDs into its own package, saytest.a
,test.b
andtest.c
and do it within the same single Maven project.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:It is is important to use different target directories for separate executions.
OK, this would create three target directories with three target packages. Next problem is that classes from
c.xsd
will generated intest.a
andtest.b
which we want to avoid.To achieve this, we have to tell XJC to use classes from
test.c
for types fromc.xsd
. This is actually what episode file is for. This file is normally generated underMETA-INF\sun-jaxb.episode
and it contains bindings for all types in the processed schema. Here's an example generated forc.xsd
:Episode file is actually a normal bindings file. So you can directly use it in compilation:
There is just one tiny problem left. Episode files generated by XJC also contain this fragment:
It effectively says "do not generate code for schema in the given namespace". This would not be a problem if
a.xsd
orb.xsd
would be in a different namespace. But since they are in the same namespace, this fragment will effectively turn off all code generation fora.xsd
orb.xsd
.To work around this we can post-process the
sun-jaxb.episode
which was generated forc.xsd
. This can be done with a simple XSLT:This XSLT should be run after the code for
c.xsd
, but before the code fora.xsd
andb.xsd
is generated. This can be achieved by putting these executions into different phases (generate-sources
,process-sources
,generate-resources
).Below is the complete
pom.xml
: