JAXB issue: cannot marshall Java object graph to XML in Servlet - nor any of its super class is known to this context
thomasseirer Apr 27, 2011 10:11 AM(Java version 1.6.0_24 and JBoss AS 6.0.0.Final (applies also to JBoss 5.1))
Trying to marshall an Java object graph to XML in a servlet I get the following apparently well known exception:
22:20:10,140 ERROR [STDERR] javax.xml.bind.MarshalException
22:20:10,140 ERROR [STDERR] - with linked exception:
22:20:10,140 ERROR [STDERR] [javax.xml.bind.JAXBException: class YY.XXX.printservice.domain.EmployeeDetails nor any of its super class is known to this context.]
(Note: I renamed the package name.)
When I try google for this problem I get hits galore.
But with the solutions and hints offered - for example the use of @XmlSeeAlso - I still wasn't able to solve the problem...
The strange thing about this is also that it works when the marshalling is done by a standalone client.
These are the two value classes involved:
1. class Report:
{code}
@XmlRootElement(name="report")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlSeeAlso(EmployeeDetails.class)
public class Report implements Serializable {
@XmlElement(name="employee", type=YY.XXXX.printservice.domain.EmployeeDetails.class)
private List<EmployeeDetails> employeeDetails;
public Report(){
}
public Report(List<EmployeeDetails> employeeDetails) {
this.employeeDetails = employeeDetails;
}
public List<EmployeeDetails> getEmployeeDetails() {
return employeeDetails;
}
public void setEmployeeDetails(List<EmployeeDetails> employeeDetails) {
this.employeeDetails = employeeDetails;
}
}
{code}
2. class EmployeeDetails:
{code}
@XmlType(
propOrder = {
"employeeId"
, "firstName"
, "lastName"
, "departmentName"
, "jobTitle"
, "salary"
}
)
@XmlAccessorType(XmlAccessType.FIELD)
public class EmployeeDetails implements Serializable {
private Long employeeId;
private String firstName;
private String lastName;
private String departmentName;
private String jobTitle;
private Float salary;
public EmployeeDetails(){
}
public EmployeeDetails(Long employeeId
, String firstName
, String lastName
, String departmentName
, String jobTitle
, Float salary) {
this.employeeId = employeeId;
this.firstName = firstName;
this.lastName = lastName;
this.departmentName = departmentName;
this.jobTitle = jobTitle;
this.salary = salary;
}
public Long getEmployeeId() {
return employeeId;
}
public void setEmployeeId(Long employeeId) {
this.employeeId = employeeId;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getDepartmentName() {
return departmentName;
}
public void setDepartmentName(String departmentName) {
this.departmentName = departmentName;
}
public String getJobTitle() {
return jobTitle;
}
public void setJobTitle(String jobTitle) {
this.jobTitle = jobTitle;
}
public Float getSalary() {
return salary;
}
public void setSalary(Float salary) {
this.salary = salary;
}
}
{code}
The relevant parts of the servlet:
{code}
public final class PrintServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@EJB(mappedName="EmployeeBean/local")
private EmployeeLocal employeeBean;
private static JAXBContext jaxbContext = null;
private FopFactory fopFactory = FopFactory.newInstance();
private TransformerFactory transformerFactory = TransformerFactory.newInstance();
private DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
public PrintServlet() {
super();
}
public void init() throws ServletException {
try {
jaxbContext = JAXBContext.newInstance( new Class[] {Report.class});
}
catch (JAXBException exception) {
exception.printStackTrace();
throw new ServletException( exception.fillInStackTrace() );
}
}
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String content = "application/x-java-serialized-object";
response.setContentType(content);
try {
List<EmployeeDetails> employeeDetailsList = employeeBean.getDetailsForAllEmployees();
Report report = new Report();
report.setEmployeeDetails(employeeDetailsList);
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.newDocument();
jaxbContext.createMarshaller().marshal(report, document);
....
{code}
Calling toString on the JAXBContext instance in the servlet shows this:
22:20:09,656 INFO [STDOUT] vfs:/D:/server/jboss-6.0.0.Final/lib/jaxb-impl.jar/com/sun/xml/bind/v2/runtime/JAXBContextImpl.class Build-Id: 2.2
22:20:09,656 INFO [STDOUT] Classes known to this context:
22:20:09,656 INFO [STDOUT] [B
22:20:09,656 INFO [STDOUT] boolean
22:20:09,656 INFO [STDOUT] byte
22:20:09,656 INFO [STDOUT] char
22:20:09,656 INFO [STDOUT] com.sun.xml.bind.api.CompositeStructure
22:20:09,656 INFO [STDOUT] YY.XXX.printservice.domain.EmployeeDetails
22:20:09,656 INFO [STDOUT] YY.XXX.printservice.domain.Report
22:20:09,656 INFO [STDOUT] double
22:20:09,656 INFO [STDOUT] float
22:20:09,656 INFO [STDOUT] int
22:20:09,656 INFO [STDOUT] java.awt.Image
22:20:09,656 INFO [STDOUT] java.io.File
22:20:09,656 INFO [STDOUT] java.lang.Boolean
22:20:09,656 INFO [STDOUT] java.lang.Byte
22:20:09,656 INFO [STDOUT] java.lang.Character
22:20:09,656 INFO [STDOUT] java.lang.Class
22:20:09,656 INFO [STDOUT] java.lang.Double
22:20:09,656 INFO [STDOUT] java.lang.Float
22:20:09,656 INFO [STDOUT] java.lang.Integer
22:20:09,656 INFO [STDOUT] java.lang.Long
22:20:09,656 INFO [STDOUT] java.lang.Object
22:20:09,656 INFO [STDOUT] java.lang.Short
22:20:09,656 INFO [STDOUT] java.lang.String
22:20:09,656 INFO [STDOUT] java.lang.Void
22:20:09,656 INFO [STDOUT] java.math.BigDecimal
22:20:09,656 INFO [STDOUT] java.math.BigInteger
22:20:09,656 INFO [STDOUT] java.net.URI
22:20:09,656 INFO [STDOUT] java.net.URL
22:20:09,656 INFO [STDOUT] java.util.Calendar
22:20:09,656 INFO [STDOUT] java.util.Date
22:20:09,656 INFO [STDOUT] java.util.GregorianCalendar
22:20:09,656 INFO [STDOUT] java.util.UUID
22:20:09,656 INFO [STDOUT] javax.activation.DataHandler
22:20:09,656 INFO [STDOUT] javax.xml.bind.JAXBElement
22:20:09,656 INFO [STDOUT] javax.xml.datatype.Duration
22:20:09,656 INFO [STDOUT] javax.xml.datatype.XMLGregorianCalendar
22:20:09,656 INFO [STDOUT] javax.xml.namespace.QName
22:20:09,656 INFO [STDOUT] javax.xml.transform.Source
22:20:09,656 INFO [STDOUT] long
22:20:09,656 INFO [STDOUT] short
22:20:09,656 INFO [STDOUT] void
Calling toString on the JAXBContext instance of the standalone client shows this:
[java] jar:file:/D:/server/jboss-6.0.0.Final/client/jaxb-impl.jar!/com/sun/xml/bind/v2/runtime/JAXBContextImpl.class Build-Id: 2.2
[java] Classes known to this context:
[java] [B
[java] boolean
[java] byte
[java] char
[java] com.sun.xml.bind.api.CompositeStructure
[java] YY.XXX.printservice.domain.EmployeeDetails
[java] YY.XXX.printservice.domain.Report
[java] double
[java] float
[java] int
[java] java.awt.Image
[java] java.io.File
[java] java.lang.Boolean
[java] java.lang.Byte
[java] java.lang.Character
[java] java.lang.Class
[java] java.lang.Double
[java] java.lang.Float
[java] java.lang.Integer
[java] java.lang.Long
[java] java.lang.Object
[java] java.lang.Short
[java] java.lang.String
[java] java.lang.Void
[java] java.math.BigDecimal
[java] java.math.BigInteger
[java] java.net.URI
[java] java.net.URL
[java] java.util.Calendar
[java] java.util.Date
[java] java.util.GregorianCalendar
[java] java.util.UUID
[java] javax.activation.DataHandler
[java] javax.xml.bind.JAXBElement
[java] javax.xml.datatype.Duration
[java] javax.xml.datatype.XMLGregorianCalendar
[java] javax.xml.namespace.QName
[java] javax.xml.transform.Source
[java] long
[java] short
[java] void
Thus the two JAXBContext instances do not only know the same data types, but they also know the two relevant custom classes Report and EmployeeDetails.
But the similarity continues: Outputting the schema known to both JAXBContext instances shows that they are also the same.
1. server side:
22:20:09,859 INFO [STDOUT] <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
22:20:09,859 INFO [STDOUT] <xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
22:20:09,859 INFO [STDOUT]
22:20:09,906 INFO [STDOUT] <xs:element name="report" type="report"/>
22:20:09,906 INFO [STDOUT]
22:20:09,906 INFO [STDOUT] <xs:complexType name="employeeDetails">
22:20:09,906 INFO [STDOUT] <xs:sequence>
22:20:09,906 INFO [STDOUT] <xs:element name="employeeId" type="xs:long" minOccurs="0"/>
22:20:09,906 INFO [STDOUT] <xs:element name="firstName" type="xs:string" minOccurs="0"/>
22:20:09,906 INFO [STDOUT] <xs:element name="lastName" type="xs:string" minOccurs="0"/>
22:20:09,906 INFO [STDOUT] <xs:element name="departmentName" type="xs:string" minOccurs="0"/>
22:20:09,906 INFO [STDOUT] <xs:element name="jobTitle" type="xs:string" minOccurs="0"/>
22:20:09,906 INFO [STDOUT] <xs:element name="salary" type="xs:float" minOccurs="0"/>
22:20:09,906 INFO [STDOUT] </xs:sequence>
22:20:09,906 INFO [STDOUT] </xs:complexType>
22:20:09,906 INFO [STDOUT]
22:20:09,906 INFO [STDOUT] <xs:complexType name="report">
22:20:09,921 INFO [STDOUT] <xs:sequence>
22:20:09,921 INFO [STDOUT] <xs:element name="employee" type="employeeDetails" minOccurs="0" maxOccurs="unbounded"/>
22:20:09,921 INFO [STDOUT] </xs:sequence>
22:20:09,921 INFO [STDOUT] </xs:complexType>
22:20:09,921 INFO [STDOUT] </xs:schema>
2. standalone client.
{code:xml}
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="report" type="report"/>
<xs:complexType name="report">
<xs:sequence>
<xs:element name="employee" type="employeeDetails" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="employeeDetails">
<xs:sequence>
<xs:element name="employeeId" type="xs:long" minOccurs="0"/>
<xs:element name="firstName" type="xs:string" minOccurs="0"/>
<xs:element name="lastName" type="xs:string" minOccurs="0"/>
<xs:element name="departmentName" type="xs:string" minOccurs="0"/>
<xs:element name="jobTitle" type="xs:string" minOccurs="0"/>
<xs:element name="salary" type="xs:float" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
{code:xml}
Why is it that the marshalling in the servlet throws an Exception and the marshalling in the standalone client gives a result like this:
{code:xml}
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<report>
<employee>
<employeeId>205</employeeId>
<firstName>Shelley</firstName>
<lastName>Higgins</lastName>
<departmentName>Accounting</departmentName>
<jobTitle>Accounting Manager</jobTitle>
<salary>12000.0</salary>
</employee>
<employee>
<employeeId>206</employeeId>
<firstName>William</firstName>
<lastName>Gietz</lastName>
<departmentName>Accounting</departmentName>
<jobTitle>Public Accountant</jobTitle>
<salary>8300.0</salary>
</employee>
<employee>
<employeeId>200</employeeId>
<firstName>Jennifer</firstName>
<lastName>Whalen</lastName>
<departmentName>Administration</departmentName>
<jobTitle>Administration Assistant</jobTitle>
<salary>4400.0</salary>
</employee>
.....
</report>
{code:xml}
Thanks in advance.