1 Reply Latest reply on Apr 27, 2011 10:15 AM by thomasseirer

    JAXB issue: cannot marshall Java object graph to XML in Servlet - nor any of its super class is known to this context

    thomasseirer

      (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.