I have a similar structure as this xsd:
<xs:element name="address">
<xs:complexType>
<xs:choice>
<xs:element name="address">
<xs:complexType>
<xs:sequence>
<!-- ... -->
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="mailbox">
<xs:complexType>
<xs:sequence>
<!-- ... -->
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
In my opinion this is a bad schema. You should not name your elements in that way. I cannot change this schema since its comming from a third party. I have to convert this into a java model. Obviously this wont work out of the box. JAXB XSD to Java would try to generate something like this:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"address",
"mailbox"
})
public static class Address implements Serializable, Cloneable, CopyTo, Equals, HashCode, MergeFrom, ToString
{
Address.Address address;
Address.Mailbox mailbox;
public static class Address implements Serializable, Cloneable, CopyTo, Equals, HashCode, MergeFrom, ToString
{
// ...
}
public static class Mailbox implements Serializable, Cloneable, CopyTo, Equals, HashCode, MergeFrom, ToString
{
// ...
}
}
Ofcourse this results in the java error Duplicate class: 'Address'.
Since I cannot change the schema I try to change the generated java class.
I remembered there was a plugin for auto name resolution. So I tried:
<plugin>
<groupId>org.jvnet.jaxb</groupId>
<artifactId>jaxb-maven-plugin</artifactId>
<version>4.0.9</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<debug>true</debug>
<args>
<!-- Enable Equals Generation -->
<arg>-Xequals</arg>
<!-- Enable Hashcode Generation -->
<arg>-XhashCode</arg>
<!-- Enable ToString Generation -->
<arg>-XtoString</arg>
<!-- Enable Builder Generation -->
<arg>-Xfluent-api</arg>
<!-- Enable Inheritance Generation -->
<arg>-Xinheritance</arg>
<!-- Enable Copy Generation -->
<arg>-Xcopyable</arg>
<!-- Enable Merge Generation -->
<arg>-Xmergeable</arg>
<!-- auto resolve conflicting names -->
<arg>-XautoNameResolution</arg>
</args>
<strict>false</strict>
<extension>true</extension>
<schemaDirectory>src/main/resources/xsd</schemaDirectory>
<bindingDirectory>src/main/resources/xjb</bindingDirectory>
<catalog>src/main/resources/xsd/external/catalog.cat</catalog>
<generateDirectory>${project.build.directory}/generated-sources</generateDirectory>
<plugins>
<plugin>
<groupId>org.jvnet.jaxb</groupId>
<artifactId>jaxb-plugins</artifactId>
<version>4.0.9</version>
</plugin>
<plugin>
<groupId>org.jvnet.jaxb</groupId>
<artifactId>jaxb-plugins-tools</artifactId>
<version>4.0.9</version>
</plugin>
</plugins>
</configuration>
</execution>
</executions>
</plugin>
But that did not change the java class generation at all. So I tried the bindings approach. I did the following:
<jxb:bindings version="3.0"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<jxb:bindings schemaLocation="schema.xsd" node="/xs:schema/xs:element[@name='address']">
<jxb:class name="Address"/>
</jxb:bindings>
<jxb:bindings schemaLocation="schema.xsd" node="/xs:schema/xs:element[@name='address']/xs:complexType/xs:choice/xs:element[@name='address']">
<jxb:class name="AddressDetails"/>
</jxb:bindings>
</jxb:bindings>
But this results in: Execution default of goal org.jvnet.jaxb:jaxb-maven-plugin:4.0.0:generate failed: Illegal class inheritance loop. Outer class Address may not subclass from inner class: Address
Im not sure what is really happening there.
Is there any way to solve that problem?
Mulgard, you are very close. To demonstrate a solution, I completed your sample schema, as follows:
SameRootChildName.xsd
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="urn:example.org:srcn"
xmlns:tns="urn:example.org:srcn"
>
<xs:element name="address">
<xs:complexType>
<xs:choice>
<xs:element name="address">
<xs:complexType>
<xs:sequence>
<xs:element name="ellipsis" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="mailbox">
<xs:complexType>
<xs:sequence>
<xs:element name="ellipsis" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
Using this example, I am able to reproduce your error using the xjc
command line tool:
xjc -d out -no-header SameRootChildName.xsd
parsing a schema...
compiling a schema...
[ERROR] Complex type and its child element share the same name "Address". Use a class customization to resolve this conflict.
line 12 of file:SameRootChildName.xsd
Failed to produce code.
Perhaps, this error message is more direct, "Complex type and its child element share ..." The complex type in the message is a reference to the anonymous type of the root level element named address
. Here is a binding file that targets that type and binds a class customization to it. The customization changes the generated root class name to AddressRoot
and leaves the child class name as Address
SameRootChildName.xjb
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jaxb:bindings jaxb:version="3.0"
xmlns:jaxb="https://jakarta.ee/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
<jaxb:globalBindings localScoping="toplevel" >
<jaxb:serializable uid="20250501" />
</jaxb:globalBindings>
<jaxb:bindings schemaLocation="SameRootChildName.xsd" node="/xs:schema">
<jaxb:bindings node="xs:element[@name='address']" >
<jaxb:class name="AddressRoot"/>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
Re-executing the `xjc' tool with the new binding file generated the classes successfully.
xjc -d out -no-header -b SameRootChildName.xjb SameRootChildName.xsd
parsing a schema...
compiling a schema...
org/example/srcn/Address.java
org/example/srcn/AddressRoot.java
org/example/srcn/Mailbox.java
org/example/srcn/ObjectFactory.java
org/example/srcn/package-info.java
This edit to the bindings file above works too:
SameRootChildName.xjb (edit)
...
<jaxb:bindings node="xs:element[@name='address']" >
<jaxb:bindings node="xs:complexType" >
<jaxb:class name="AddressRoot"/>
</jaxb:bindings>
</jaxb:bindings>
...
Alternatively, this variant of the bindings file works by changing the name of the child class instead of the root class.
SameRootChildName2.xjb
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jaxb:bindings jaxb:version="3.0"
xmlns:jaxb="https://jakarta.ee/xml/ns/jaxb"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
>
<jaxb:globalBindings localScoping="toplevel" >
<jaxb:serializable uid="20250501" />
</jaxb:globalBindings>
<jaxb:bindings schemaLocation="SameRootChildName.xsd" node="/xs:schema">
<jaxb:bindings node="xs:element[@name='address']" >
<jaxb:bindings node="xs:complexType" >
<jaxb:bindings node="xs:choice" >
<jaxb:bindings node="xs:element[@name='address']" >
<jaxb:bindings node="xs:complexType" >
<jaxb:class name="AddressDetails"/>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
The result is shown here:
xjc -d out -no-header -b SameRootChildName2.xjb SameRootChildName.xsd
parsing a schema...
compiling a schema...
org/example/srcn/Address.java
org/example/srcn/AddressDetails.java
org/example/srcn/Mailbox.java
org/example/srcn/ObjectFactory.java
org/example/srcn/package-info.java