简体   繁体   中英

JAXB: Generating classes for two XSDs which share a common XSD

I have 2 service XSD files AService.xsd and BService.xsd each with different targetNamespace. Both of these use a common XSD called common.xsd. I use the JAXB Maven plugin to generate classes. Here's how,

<execution>
    <id>generate-package</id>
    <goals>
        <goal>generate</goal>
    </goals>
    <configuration>
        <extension>true</extension>
        <schemaIncludes>
            <include>schema/Aservice.xsd</include>
            <include>schema/Bservice.xsd</include>                             
        </schemaIncludes>
        <bindingIncludes>                                   
            <include>schema/*.xjb</include>
        </bindingIncludes>
        <generatePackage>com.schema</generatePackage>
        <generateDirectory>src/main/java</generateDirectory>
    </configuration>
</execution>

When i try to run this i get the following error. ValidationType is defined in common.xsd

org.xml.sax.SAXParseException: A class/interface with the same name "com.schema.ValidationType" is already in use. Use a class customization to resolve this conflict.
..........
org.xml.sax.SAXParseException: (Relevant to above error) another "ValidationType" is generated from here.
......
com.sun.istack.SAXParseException2: Two declarations cause a collision in the ObjectFactory class.

If i run the 2 service xsds in 2 different executions generating into 2 different packages, i get the same ValidationType class in 2 different packages.

Any ideas on how to make JAXB recognize shared schemas?

You are facing a so-called "chameleon schema" which is considered to be a bad practice. Unfortunately, there is no good solution due to the nature of JAXB. JAXB annotation bind bean properties to XML elements and attributes in specific namespaces (determined in the schema compile time). So once your schema is compiled, there is no official good way to change namespaces of elements and attributes your properties are bound to.

However, this is exactly what you want to achieve with "chameleon" schemas. Classes derived from "common.xsd" should somehow magically map to namespace A if used in A classes and to namespace B if used in B classes. I can imagine this magic, but never seen in in real life.

Since you essentially want A/common and B/common to be the "same thing", one of the ways to resolve it is to generate A and B (both with common) in two executions and to make common classes implement a certain "common" interface. Then your software could process A/common and B/common in the same faschion regardless of the fact that these are actually classes from the different packages.

UPDATE:

From the comment I see that you don't have a chameleon schema, but just a normal importing. It is easy then, just compile common, A and B separately. See the Separate schema compilation for maven-jaxb2-plugin.

I customized the packages as described here . So common.xsd goes in com.common.schema and is shared by AService.xsd and BService.xsd which are both in different packages themselves, since they are in different namespaces.

The generatePackage is removed from the maven configuration and looks like this,

<execution>
    <id>generate-package</id>
    <goals>
        <goal>generate</goal>
    </goals>
    <configuration>
        <extension>true</extension>
        <schemaIncludes>
            <include>schema/Aservice.xsd</include>
            <include>schema/Bservice.xsd</include>                            
        </schemaIncludes>
        <bindingIncludes>
            <include>schema/*.xjb</include>
        </bindingIncludes>                                
        <generateDirectory>src/main/java</generateDirectory>
    </configuration>
</execution>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM