JAXB namespace issue with extended annotated class' member
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 !
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>
WA 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>
链接地址: http://www.djcxy.com/p/51716.html
上一篇: 如何覆盖CXF中根类型的camelcase(wadl2java)
下一篇: JAXB命名空间问题与扩展注释类的成员