Using maven jaxb2 plugin, modular compilation using episode and catalog throws Malformed URL error

2.6k views Asked by At

My project contains A.xsd which imports schema as follows from B.xsd which is part of another project:

<xsd:import namespace="http://com.test.schema/common/Context" schemaLocation="http://com.test.schema/common/Context/B.xsd"/>

I am trying to use the episode from the project which contains B.xsd so that classes related to B.xsd do not get re-generated when A.xsd is parsed. So I referred this and this to come up with the following configuration: Here is the pom.xml

    <dependencies>
        <dependency>
            <groupId>com.bar.foo</groupId>
            <artifactId>schema-b</artifactId>
            <version>1.2</version>
        </dependency>
    <dependencies>
    .
    .
    .
    .
    .
    <build>
        <plugins>
        <dependency>
            <plugin>
                <groupId>org.jvnet.jaxb2.maven2</groupId>
                <artifactId>maven-jaxb2-plugin</artifactId>
                <version>0.13.0</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                        <configuration>
                            <extension>true</extension>
                            <episodes>
                                <episode>
                                    <groupId>com.bar.foo</groupId>
                                    <artifactId>schema-b</artifactId>
                                </episode>
                            </episodes>
                            <catalog>src/main/resources/catalog.cat</catalog>
                            <schemas>
                                <schema>

                                    <fileset>
                                        <directory>${basedir}/src/main/schemas</directory>
                                        <includes>
                                            <include>A.xsd</include>
                                            <include>...</include>
                                            <include>...</include>
                                        </includes>
                                    </fileset>
                                </schema>
                            </schemas>
                            <bindingDirectory>${basedir}/src/main/schemas</bindingDirectory>
                            <bindingIncludes>
                                <include>*.xjb</include>
                            </bindingIncludes>
                            <args>
                                <arg>-Xannotate</arg>
                            </args>
                            <plugins>
                                <plugin>
                                    <groupId>org.jvnet.jaxb2_commons</groupId>
                                    <artifactId>jaxb2-basics</artifactId>
                                    <version>0.6.0</version>
                                </plugin>
                                <plugin>
                                    <groupId>org.jvnet.jaxb2_commons</groupId>
                                    <artifactId>jaxb2-basics-annotate</artifactId>
                                    <version>0.6.0</version>
                                </plugin>
                            </plugins>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

Here is the catalog file:

PUBLIC "http://com.test.schema/common/Context" "maven:com.bar.foo:schema-a:jar::1.2!"

There is some configuration in the xjb file to make sure that XmlRootElement is written into some generated classes:

<jxb:bindings xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
jxb:version="2.1" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:annox="http://annox.dev.java.net" extensionBindingPrefixes="xjc">
<jxb:globalBindings>
    <xjc:simple />
</jxb:globalBindings>   
<jxb:bindings
    schemaLocation="A.xsd">
    <jxb:bindings node="//xsd:complexType[@name='ADataType']">
        <jxb:class name="AData" />
        <annox:annotate>
            <annox:annotate annox:class="javax.xml.bind.annotation.XmlRootElement"
                name="AData" />
        </annox:annotate>
    </jxb:bindings>
</jxb:bindings>

Inspite of providing the episode to the xjc execution and the location of the schema for B.xsd in the catalog file, the classes for B.xsd is getting generated.

The issue is that the maven artifact referred to by the catalog file is not being picked up. I see the following error in the maven build logs:

Malformed URL on system identifier: maven:com.bar.foo:schema-b:jar::1.2!
PUBLIC: http://com.test.schema/common/Context
maven:com.bar.foo:schema-a:jar::1.2!

Can anyone help tell me why am I hitting this malformed URL error for the artifact that contains B.xsd? Any help will be really appreciated.

1

There are 1 answers

3
lexicore On BEST ANSWER

Disclaimer: I'm the author of the .

First, you're probably mixing A and B here. You're saying A imports B but then you're using the schema-a artifact as episode. If B is imported, you should use schema-b as episode to not regenerate B stuff when compiling A.

But I think this is probably just a minor mistake in the question.

You have two aspects here - episodes and catalogs.

Episodes allow you to skip generation of classes you've generated somewhere else already. So if you use schema-b artifact when compiling schema-a then XJC should not generate classes for schema-b. You don't need catalogs for that, it's independent.

Sometimes XJC still generates few leftovers - even if you use an episode. I often get ObjectFactory and maybe some enums or top-level-elements generated. I believe this is an issue in XJC, there's nothing I can do in the about it.
So as a workaround I just use maven-antrun-plugin to delete unnecessary generated things.

If you get all of the B stuff generated then you should check if schema-b artifact really have the episode file generated. Check if you have META-INF/sun-jaxb.episode inside the JAR. See this answer for some trivia on the episode file.

So if you correctly configure the correct episode artifact you should not get B things generated, you don't need catalogs for this.

What you need the catalog for is to avoid downloading http://com.test.schema/common/Context/B.xsd when compiling. You can use catalogs to point to anothe location. I think your problem here is that you refer http://com.test.schema/common/Context to maven:com.bar.foo:schema-a:jar::1.2! which obviously does not point to the schema resource.

If you have an import like

<xsd:import namespace="http://com.test.schema/common/Context" schemaLocation="http://com.test.schema/common/Context/B.xsd"/>

Then you should probably rewrite it as follows:

PUBLIC "http://com.test.schema/common/Context" "maven:com.bar.foo:schema-b:jar::1.2!/common/Context/B.xsd"

Assuming schema-b artifact contains your schema under /common/Context/B.xsd. Note that it maps namespace, not schema location.

You can also use REWRITE_SYSTEM to rewrite schema location. For example:

REWRITE_SYSTEM "http://com.test.schema" "maven:com.bar.foo:schema-b:jar::1.2!"

If you have an URL like http://com.test.schema/common/Context/B.xsd, it will be rewritten to maven:com.bar.foo:schema-b:jar::1.2!/common/Context/B.xsd. This will point to the resource /common/Context/B.xsd inside your schema-b JAR.

Another hint - if you use schema-b as dependency in your project, you can omit the version.

Here's an example of catalog from a real world project:

https://github.com/highsource/ogc-schemas/blob/master/schemas/src/main/resources/ogc/catalog.cat

It contains rewrites like:

REWRITE_SYSTEM "http://schemas.opengis.net" "maven:org.jvnet.ogc:ogc-schemas:jar::!/ogc"