Question

I have 3 annotated classes (I deliberatly removed getters, setters, and so on to make code more readable):

Result.java

@XmlRootElement(name = "resultat")
@XmlType(propOrder = { "state", "content" })
public class Result {
    protected State state;
    protected Content content;
}

Content.java:

@XmlRootElement(name = "content")
@XmlSeeAlso({ Job.class })
public class Content {
}

and Job.java which extends Content:

@XmlType(name = "job", propOrder = { "status" })
@XmlRootElement(name = "job")
public class JobStatus extends Content {
    protected String status;
}

I am setting a Job instance as the value of the content member of the result class, but i get the following generated xml file:

<result>
    <state>
        <tag>value</tag>
    </state>
    <content xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="job">
        <status>ok</status>
    </content>
</result>

But it is not a valid xml file and i can not validate it against the following schema because of the "xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="job"" part since job is not a type from http://www.w3.org/2001/XMLSchema-instance.

<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="result">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="state">
          <xs:complexType>
            <xs:sequence>
              <xs:element type="xs:string" name="tag"/>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
        <xs:element name="content">
          <xs:complexType>
            <xs:sequence>
              <xs:element type="xs:string" name="status"/>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>

How can i change my JAXB configuration to avoid this problem ?

Thanks !

Was it helpful?

Solution

The problem is not in the JAXB configuration, but in the design of the Schema vs the Java Classes.

The Java Class Content does not comply with your Schema, since the element status is defined in the Schema but not in the Java Class. Also, you do not define job in your Schema.

The attribute xsi:type is used for inheritance. Since your JobStatus Class inherits from Content, in XML its displayed as content of type job.

I think the best solution is to remove the element status from content in your Schema and then define job in your Schema, like so:

<complexType name="job">
    <complexContent>
        <extension base="content">
            <sequence>
                <xs:element type="xs:string" name="status"/>
            </sequence>
        </extension>
    </complexContent>
</complexType>

OTHER TIPS

W A is correct that your JAXB implementation is doing exactly what you told it to do (see: http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-xsitype.html). If you don't want to change your XML schema, below is how you can change your mappings.

Java Model

Result

We will use the @XmlElement annotation on the content field to indicate that the real type is Job (see: http://blog.bdoughan.com/2011/05/jaxb-and-interface-fronted-models.html).

import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlType(propOrder = { "state", "content" })
@XmlAccessorType(XmlAccessType.FIELD)
public class Result {
    protected State state;

    @XmlElement(type=Job.class)
    protected Content content;
}

Content

We will use the @XmlTransient annotation on the Content class to remove it from the inheritance hierarchy (see: http://blog.bdoughan.com/2011/06/ignoring-inheritance-with-xmltransient.html).

import javax.xml.bind.annotation.XmlTransient;

@XmlTransient
public class Content {
}

Job

Job is mapped normally.

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
public class Job extends Content {
    protected String status;
}

Demo Code

Demo

import java.io.File;
import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Result.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum17993543/input.xml");
        Result result = (Result) unmarshaller.unmarshal(xml);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(result,System.out);
    }

}

input.xml/Output

<?xml version="1.0" encoding="UTF-8"?>
<result>
    <state>
        <tag>value</tag>
    </state>
    <content>
        <status>ok</status>
    </content>
</result>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top