JAXB2 - XJC - Problem with XmlElement.type on generated class

106 Views Asked by At

TLDR: I have to generate Java classes from an XSD, and one of the fields of the "Main" object is another generated class. The field has an annotation @XmlElement, which has a property "type = Object.class " while having the field type = "SubObject". This makes it so that when I try to unmarshal the XML into a Java Object I get an error.

@XmlRootElement(name = "MainObject")
public class MainObject {
    @XmlElement(name = "SubObject", required = true, type = Object.class)
    protected SubObject subObject;
}

I have tried with both the JAXB2 Maven Plugin and the Apache-CXF-XJC plugin. In both cases I end up with the same result. If I manually remove the type property from the annotation it works. How can I generate the class without the type property, or make it be SubObject.class in this case?

More info

The files/configuration that worked on the old project:

pom.xml plugin configuration
<plugin>
    <groupId>org.apache.cxf</groupId>
    <artifactId>cxf-xjc-plugin</artifactId>
    <version>2.3.0</version>
    <configuration>
        <extensions>
            <extension>org.apache.cxf.xjcplugins:cxf-xjc-dv:2.3.0</extension>
        </extensions>
    </configuration>
    <executions>
        <execution>
            <id>generate-sources</id>
            <phase>generate-sources</phase>
            <goals>
                <goal>xsdtojava</goal>
            </goals>
            <configuration>
                <sourceRoot>${project.build.sourceDirectory}/../generated/</sourceRoot>
                <xsdOptions>
                    <xsdOption>
                        <xsd>src/main/resources/xsd/subobject.xsd</xsd>
                        <packagename>org.acme.generated</packagename>
                    </xsdOption>                    
                    <xsdOption>
                        <xsd>src/main/resources/xsd/mainobject.xsd</xsd>
                        <packagename>org.acme.generated</packagename>
                        <bindingFile>src/main/resources/xsd/bindings.xjb</bindingFile>
                    </xsdOption>
                </xsdOptions>
            </configuration>
        </execution>
    </executions>
</plugin>
xjb bindings file
<bindings xmlns="http://java.sun.com/xml/ns/jaxb" xmlns:xsi="http://www.w3.org/2000/10/XMLSchema-instance"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.1">
    <bindings schemaLocation="mainobject.xsd" version="1.0">
        <bindings node="//xs:element[@name='SubObject']">
                <class ref="org.acme.generated.SubObject"/>
        </bindings>
    </bindings>
</bindings>
generated MainObject class
@XmlRootElement(name = "MainObject")
public class MainObject {

    @XmlElement(name = "MainElement1", required = true)
    protected String mainElement1;
    @XmlElement(name = "MaintElement2")
    protected int maintElement2;
    @XmlElement(name = "SubObject", required = true)
    protected SubObject subObject;

Now, after researching a bit, I've ended up with the following files for the newer plugin:

pom.xml plugin configuration
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>jaxb2-maven-plugin</artifactId>
    <version>3.1.0</version>
    <executions>
      <execution>
        <id>xjc</id>
        <goals>
          <goal>xjc</goal>
        </goals>
      </execution>
    </executions>
    <configuration>
      <sources>src/main/resources/xsd</sources>
      <outputDirectory>src/main/generated</outputDirectory>
      <xjbSources>
        <xjbSource>src/main/resources/xjb</xjbSource>
      </xjbSources>
      <!-- The package of your generated sources -->
      <packageName>org.acme.generated</packageName>
    </configuration>
</plugin>
xjb bindings file
<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings xmlns:jaxb="https://jakarta.ee/xml/ns/jaxb"
               xmlns:xsd="http://www.w3.org/2001/XMLSchema"
               xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
               jaxb:extensionBindingPrefixes="xjc"
               version="3.0">
    <jaxb:bindings schemaLocation="..\xsd\mainobject.xsd" version="1.0" node="//xsd:element[@name='SubObject']">
        <jaxb:property>
            <jaxb:baseType>
                <jaxb:javaType name="org.acme.generated.SubObject"/>
            </jaxb:baseType>
        </jaxb:property>
    </jaxb:bindings>
</jaxb:bindings>

generated MainObject class
@XmlRootElement(name = "MainObject")
public class MainObject {

    @XmlElement(name = "MainElement1", required = true)
    protected String mainElement1;
    @XmlElement(name = "MaintElement2")
    protected int maintElement2;
    @XmlElement(name = "SubObject", required = true, type = Object.class)
    protected SubObject subObject;
generated SubObject class
@XmlRootElement(name = "SubObject")
public class SubObject {

    @XmlElement(name = "SubElement1", required = true)
    protected String subElement1;
    @XmlElement(name = "SubElement2")
    protected int subElement2;

Both the xsd files stayed the same, but the generated MainObject class now has the type property on the anottation, with value Object.class. When I try to unmarshal the following XML:

<?xml version="1.0" encoding="utf-8"?>
<MainObject>
    <MainElement1>test1</MainElement1>
    <MainElement2>2</MainElement2>
    <SubObject>
        <SubElement1>test1</SubElement1>
        <SubElement2>2</SubElement2>
    </SubObject>
</MainObject>

I get the following error java.lang.IllegalArgumentException: Can not set org.acme.generated.SubObject field org.acme.generated.MainObject.subObject to com.sun.org.apache.xerces.internal.dom.ElementNSImpl. However, if I manually remove the type = Object.class from the generated class the unmarshal works perfectly. To add a little bit more info, I've also tried generating the classes with an updated version of the apache-CXF-XJC plugin (v4.0.0) but I get the same result.

Is there a way to manipulate the type attribute generated on the annotation @XmlElement? Or to ignore it at the time of unmarshalling the data into an object?

0

There are 0 best solutions below