Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I generate classes from outside XSD file using JAXB XJC

Tags:

java

jaxb

xsd

xjc

I have two projects:

A /src/main/resources/schema.xsd pom.xml

B /src/main/gen pom.xml

I want in B project generate classes from XSD, that exists in A Project

In pom.xml of B project I have:

<dependencies>
    <dependency>
        <groupId>test</groupId>
        <artifactId>A</artifactId>
        <version>${project.version}</version>
    </dependency>
</dependencies>
<build>
    <plugins>
       <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>jaxb2-maven-plugin</artifactId>
        <executions>
            <execution>
                <id>xjc</id>
                <goals>
                    <goal>xjc</goal>
                </goals>
            </execution>
            </executions>
            <configuration>
                <schemaDirectory>src/main/resources</schemaDirectory>
                <outputDirectory>src/main/gen</outputDirectory>
            </configuration>
        </plugin>
    </plugins>

</build>

But xsd file is not found in classpath:

Failed to execute goal org.codehaus.mojo:jaxb2-maven-plugin:1.5:xjc (xjc) on project B: No schemas have been found

How can I use xsd from another project?

like image 542
wajs Avatar asked Dec 20 '22 10:12

wajs


1 Answers

My maven-jaxb2-plugin supports separate schema compilation.

How to do this:

  • Add your artifact a as episode.
  • If a.xsd is imported into b.xsd, you have to make this schema available to JAXB when compiling b:
    • One way to do this is to extract a.xsd from the artifact a using Maven dependency plugin, for instance.
    • Another way would be to use a catalog file to rewrite the location of a.xsd into the artifact a

See this test project for example.

The project a is totally unspectacular. Just compiles the schema a.xsd.

The project b is more interesting. Let's take a look.

pom.xml:

        <plugin>
            <groupId>org.jvnet.jaxb2.maven2</groupId>
            <artifactId>maven-jaxb2-plugin</artifactId>
            <configuration>
                <catalog>src/main/resources/catalog.cat</catalog>
                <episodes>
                    <episode>
                        <groupId>org.jvnet.jaxb2.maven2</groupId>
                        <artifactId>maven-jaxb2-plugin-tests-MAVEN_JAXB2_PLUGIN-82-a</artifactId>
                    </episode>
                </episodes>
            </configuration>
        </plugin>

The configuration says use the artifact a as episode. So when JAXB/XJC meets classes compiled in a, it will reuse them instead of generating new ones.

By the way, you can use the useDependenciesAsEpisodes instead of configuring individual episodes. In this case all the dependencies will be treated as episodes which is very convenient (less configuration).

The configuration also says to use the catalog file:

REWRITE_SYSTEM "http://www.ab.org" "maven:org.jvnet.jaxb2.maven2:maven-jaxb2-plugin-tests-MAVEN_JAXB2_PLUGIN-82-a:jar::!"

This instructs JAXB/XJC to rewrite all schema URLs starting with http://www.ab.org to start with maven:org.jvnet.jaxb2.maven2:maven-jaxb2-plugin-tests-MAVEN_JAXB2_PLUGIN-82-a:jar::! instead. The latter will be processed by the maven-jaxb2-plugin and finally resolved to the resource in a.

Let's take a closer look. The schema b.xsd imports http://www.ab.org/a.xsd:

<import namespace="urn:a" schemaLocation="http://www.ab.org/a.xsd"/>

This will be rewritten to maven:org.jvnet.jaxb2.maven2:maven-jaxb2-plugin-tests-MAVEN_JAXB2_PLUGIN-82-a:jar::!/a.xsd which will be resolved to the a.xsd inside the JAR of the project a. So, finally, JAXB/XJC will be able to read this schema from the a's JAR artifact.

You can also use PUBLIC instead of REWRITE_SYSTEM to reference a.xsd per namespace URI instead of schema location (which is logically better):

PUBLIC "urn:a" "maven:org.jvnet.jaxb2.maven2:maven-jaxb2-plugin-tests-MAVEN_JAXB2_PLUGIN-82-a:jar::!/a.xsd"

However there's a bug in JAXB/XJC this does not work if you have schemaLocation in your xs:import.

This would work at the moment:

<xsd:import namespace="urn:a"/>

This won't work at the moment:

<xsd:import namespace="urn:a" schemaLocation="a.xsd"/>

I've sent Oracle a pull request which fixes that but it's not applied yet.

The explanation above applies to the maven-jaxb2-plugin and works in versions 0.10.0 and higher.

Your original question is about jaxb2-maven-plugin from Codehaus which is a different Maven plugin. This plugin does not have all the features I've described above, but at least episodes should work via arguments. Catalogs must also work, but I believe, jaxb2-maven-plugin does not support resolving schemas in Maven artifacts. You can use the maven-dependency-plugin to extract a.xsd from artifact a instead.

SO disclaimer: I am the author of the maven-jaxb2-plugin.

Note for reviewers: it is NOT my intention here to push/advertise my plugin, I just want to provide a solution to the asked question. And it appears that my project offers the best/most elegant and full solution.

like image 157
lexicore Avatar answered Dec 29 '22 00:12

lexicore