【问题标题】:javax.xml.bind.JAXBException: Class *** nor any of its super class is known to this contextjavax.xml.bind.JAXBException: Class *** 或其任何超类对此上下文都是已知的
【发布时间】:2012-12-13 00:51:01
【问题描述】:

我正在尝试通过 REST Web 服务传递一个对象。以下是我的课程使用一些示例代码解释了我需要的功能。

Rest Web Service 类方法

@POST
@Path("/find")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces({MediaType.APPLICATION_JSON})
public Response getDepartments(){
    Response response = new Response();

    try {

        response.setCode(MessageCode.SUCCESS);
        response.setMessage("Department Names");
        Department dept = new Department("12", "Financial");
        response.setPayload(dept);

    } catch (Exception e) {
        response.setCode(MessageCode.ERROR);
        response.setMessage(e.getMessage());
        e.printStackTrace();
    }       
    return response;
}

响应类

import java.io.Serializable;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement

public class Response implements Serializable{

    private static final long serialVersionUID = 1L;

    public enum MessageCode {
        SUCCESS, ERROR, UNKNOWN
    }

    private MessageCode code;
    private String message;
    private Object payload;

    public MessageCode getCode() {
        return code;
    }

    public void setCode(MessageCode code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Object getPayload() {
        return payload;
    }

    public void setPayload(Object payload) {
        this.payload = payload;
    }
}

部门类

@XmlRootElement
public class Department implements java.io.Serializable {


    private String deptNo;
    private String deptName;


    public Department() {
    }

    public Department(String deptNo, String deptName) {
        this.deptNo = deptNo;
        this.deptName = deptName;
    }

    public String getDeptNo() {
        return this.deptNo;
    }

    public void setDeptNo(String deptNo) {
        this.deptNo = deptNo;
    }

    public String getDeptName() {
        return this.deptName;
    }

    public void setDeptName(String deptName) {
        this.deptName = deptName;
    }

}

当我在其余 Web 服务类中调用 getDepartments 方法时,它会返回以下异常。但是,如果我在 Response 类中将 payload 的类型 Object 更改为 Department ,它会正确返回 json 响应。但是由于我需要将此 Response 类用于不同类型的类,因此我无法将有效负载重新字符串化为一种类类型。有人可以帮我解决这个问题吗?

堆栈跟踪

Dec 27, 2012 9:34:18 PM com.sun.jersey.spi.container.ContainerResponse logException
SEVERE: Mapped exception to response: 500 (Internal Server Error)
javax.ws.rs.WebApplicationException: javax.xml.bind.MarshalException
 - with linked exception:
[javax.xml.bind.JAXBException: class Department nor any of its super class is known to this context.]
    at com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider.writeTo(AbstractRootElementProvider.java:159)
    at com.sun.jersey.spi.container.ContainerResponse.write(ContainerResponse.java:306)
    at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1437)
    at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1349)
    at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1339)
    at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:416)
    at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537)
    at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:699)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
    at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
    at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:401)
    at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
    at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
    at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:766)
    at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:450)
    at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
    at org.mortbay.jetty.Server.handle(Server.java:326)
    at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
    at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:945)
    at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:756)
    at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
    at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
    at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:410)
    at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
Caused by: javax.xml.bind.MarshalException
 - with linked exception:
[javax.xml.bind.JAXBException: class Department nor any of its super class is known to this context.]
    at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:323)
    at com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:177)
    at com.sun.jersey.json.impl.BaseJSONMarshaller.marshallToJSON(BaseJSONMarshaller.java:103)
    at com.sun.jersey.json.impl.provider.entity.JSONRootElementProvider.writeTo(JSONRootElementProvider.java:136)
    at com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider.writeTo(AbstractRootElementProvider.java:157)
    ... 23 more
Caused by: javax.xml.bind.JAXBException: class Department nor any of its super class is known to this context.
    at com.sun.xml.bind.v2.runtime.XMLSerializer.reportError(XMLSerializer.java:250)
    at com.sun.xml.bind.v2.runtime.XMLSerializer.reportError(XMLSerializer.java:265)
    at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:657)
    at com.sun.xml.bind.v2.runtime.property.SingleElementNodeProperty.serializeBody(SingleElementNodeProperty.java:156)
    at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:344)
    at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsSoleContent(XMLSerializer.java:597)
    at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeRoot(ClassBeanInfoImpl.java:328)
    at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:498)
    at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:320)
    ... 27 more
Caused by: javax.xml.bind.JAXBException: class Department nor any of its super class is known to this context.
    at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getBeanInfo(JAXBContextImpl.java:611)
    at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:652)
    ... 33 more

【问题讨论】:

  • 您应该接受提供的答案,因为它工作正常。
  • @Shanaka 接受提供的答案之一,#Bogdan 答案非常好。选择最佳答案并帮助他人明智地选择

标签: java rest jaxb jax-rs


【解决方案1】:

JAX-RS 实现自动支持基于可发现 JAXB 注释的类的编组/解编组,但由于您的有效负载被声明为 Object,我认为创建的 JAXBContext 错过了 Department 类以及何时编组它不知道怎么做。

快速而肮脏的解决方法是在响应类中添加 XmlSeeAlso 注释:

@XmlRootElement
@XmlSeeAlso({Department.class})
public class Response implements Serializable {
  ....

或者更复杂一点的方法是使用ContextResolver“丰富”Response 类的 JAXB 上下文:

import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;

@Provider
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public class ResponseResolver implements ContextResolver<JAXBContext> {
    private JAXBContext ctx;

    public ResponseResolver() {
        try {
            this.ctx = JAXBContext.newInstance(

                        Response.class, 
                        Department.class

                    );
        } catch (JAXBException ex) {
            throw new RuntimeException(ex);
        }
    }

    public JAXBContext getContext(Class<?> type) {
        return (type.equals(Response.class) ? ctx : null);
    }
}

【讨论】:

  • 我有对象中的对象列表。由@XmlSeeAlso 标签解决。谢谢!
  • 当我使用 XmlSeeAlso 注释时,它会将此信息添加到节点: xmlns:xsi="w3.org/2001/XMLSchema-instance" xsi:type="my_class" 是否可以选择删除它?
  • @MrJedi 你找到解决办法了吗?
  • @ariabele 你解决了吗?
【解决方案2】:

我有同样的问题,我通过向 Jaxb2marshaller 添加要探索的包来解决它。对于 spring 将定义一个这样的 bean:

@Bean
    public Jaxb2Marshaller marshaller() {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        String[] packagesToScan= {"<packcge which contain the department class>"};
        marshaller.setPackagesToScan(packagesToScan);
        return marshaller;
    }

通过这种方式,如果您的所有请求和响应类都在同一个包中,则无需在 JAXBcontext 上专门指明类

【讨论】:

    【解决方案3】:

    这个异常可以通过指定一个完整的类路径来解决。

    示例:

    如果您使用的是名为 ExceptionDetails 的类


    错误的参数传递方式

    JAXBContext jaxbContext = JAXBContext.newInstance(ExceptionDetails.class);
    

    传递参数的正确方式

    JAXBContext jaxbContext = JAXBContext.newInstance(com.tibco.schemas.exception.ExceptionDetails.class);
    

    【讨论】:

    • 如果您在不同的包中有两个不同版本的 ExceptionDetails 并且导入语句使用的是“其他”版本,那么肯定指定包会有所不同吗?
    【解决方案4】:

    我在使用 JAXB 参考实现和 JBoss AS 7.1 时遇到了类似的问题。我能够编写一个集成测试,确认 JAXB 在 JBoss 环境之外工作(暗示问题可能是 JBoss 中的类加载器)。

    这是给出错误的代码(即不工作):

    private static final JAXBContext JC;
    
    static {
        try {
            JC = JAXBContext.newInstance("org.foo.bar");
        } catch (Exception exp) {
            throw new RuntimeException(exp);
        }
    }
    

    这是有效的代码(ValueSet 是从我的 XML 编组的类之一)。

    private static final JAXBContext JC;
    
    static {
        try {
            ClassLoader classLoader = ValueSet.class.getClassLoader();
            JC = JAXBContext.newInstance("org.foo.bar", classLoader);
        } catch (Exception exp) {
            throw new RuntimeException(exp);
        }
    }
    

    在某些情况下,我得到了 Class,也没有它的任何超类在此上下文中是已知的。在其他情况下,我也遇到了 org.foo.bar.ValueSet 无法转换为 org.foo.bar.ValueSet 的异常(类似于此处描述的问题:ClassCastException when casting to the same class)。

    【讨论】:

      【解决方案5】:

      Ftrujillo's answer 效果很好,但如果您只有一个要扫描的包裹,这是最短的形式::

          @Bean
          public Jaxb2Marshaller marshaller() {
              Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
              marshaller.setContextPath("your.package.to.scan");
              return marshaller;
          }
      

      【讨论】:

        【解决方案6】:

        当我们为 Jaxb2Marshaller 使用相同的方法名称时会发生此错误 例如:

            @Bean
            public Jaxb2Marshaller marshallerClient() {
                Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
                // this package must match the package in the <generatePackage> specified in
                // pom.xml
                marshaller.setContextPath("library.io.github.walterwhites.loans");
        
                return marshaller;
            }
        

        在其他文件上

            @Bean
            public Jaxb2Marshaller marshallerClient() {
                Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
                // this package must match the package in the <generatePackage> specified in
                // pom.xml
                marshaller.setContextPath("library.io.github.walterwhites.client");
        
                return marshaller;
            }
        

        即使是不同的类,你也应该不同的命名

        【讨论】:

          【解决方案7】:

          我在支持一个应用程序时遇到了类似的错误。这是关于为 SOAP Web 服务生成的类。

          这个问题是由于缺少类引起的。当 javax.xml.bind.Marshaller 试图编组 jaxb 对象时,它没有找到使用 wsdl 和 xsd 生成的所有依赖类。在类路径中添加包含所有类的 jar 后,问题已解决。

          【讨论】:

            【解决方案8】:

            我知道这是一个老问题,但您可以使用参数 (P) 更改响应:

            public class Response<P> implements Serializable{
            
            private static final long serialVersionUID = 1L;
            
            public enum MessageCode {
                SUCCESS, ERROR, UNKNOWN
            }
            
            private MessageCode code;
            private String message;
            private P payload;
            
            ...
            public P getPayload() {
                return payload;
            }
            
            public void setPayload(P payload) {
                this.payload = payload;
            }
            

            }

            方法是

            public Response<Departments> getDepartments(){...}
            

            我现在无法尝试,但应该可以。

            否则可以扩展响应

            @XmlRootElement    
            public class DepResponse extends Response<Department> {<no content>}
            

            【讨论】:

              【解决方案9】:

              就像@ftrujillo 已经提出的那样,如果您使用 Spring Jaxb2Marshaller,您可以设置要扫描的包。在某些情况下,如果有一个更复杂的具有继承的 XSD 模型或只是具有更广泛的模型,那么在获取要扫描的包的类层次结构中的信息可能会出现问题,那么您可以使用对象层次结构的扫描.在这种情况下,我利用了以下功能,处理普通 POJO 层次结构(我相信它可能会针对非简单 POJO 进行增强):

              ....
                          Jaxb2Marshaller locMarshaller = new Jaxb2Marshaller();
                          locMarshaller.setPackagesToScan(
                                  resolveJaxb2MarshallerPackagesToScan(
                                          someFaultContentContainerClass,
                                          someFaultContentClass
                                  )
                          );
              ...
              
                  /**
                   * Resolves the packages which have to be passed into the Spring Jaxb2Marshaller
                   * to be able to perform the serialization/deserialization action
                   * @param aClassesToBeMarshalled classes which has to be marshalled. Null array items
                   *   are ignored without any error.
                   * @return packages which have to be scanned by Spring Jaxb2Marshaller for it.
                   */
                  public static String[] resolveJaxb2MarshallerPackagesToScan(Class<?>... aClassesToBeMarshalled) {
                      List<String> locResultList = new ArrayList<>();
                      for (Class<?> locProcessedTopLevelClass : aClassesToBeMarshalled) {
                          Class<?> locProcessedClass = locProcessedTopLevelClass;
                          while (locProcessedClass != null) {
                              if (!locResultList.contains(locProcessedClass.getPackageName()))
                                  locResultList.add(locProcessedClass.getPackageName());
                              locProcessedClass = locProcessedClass.getSuperclass();
                          }
                      }
                      return locResultList.toArray(new String[0]);
                  }
              
              
              

              【讨论】:

                【解决方案10】:

                我有一个类似的错误,同样的错误信息,但不同的原因。

                在我的情况下,问题是一个不完整的 ObjectFactory 实现,它自动创建为空。在为我的主类编写 ObjectFactory 后,问题就解决了。

                @XmlRegistry
                public class ObjectFactory {
                
                    /**
                     * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: x
                     * 
                     */
                    public ObjectFactory() {
                    }
                
                    public CartaPorte createCartaPorte() {
                        return new CartaPorte();
                    }
                }
                

                【讨论】:

                  猜你喜欢
                  • 2013-09-13
                  • 2021-05-27
                  • 1970-01-01
                  • 2014-07-03
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2014-08-16
                  • 1970-01-01
                  相关资源
                  最近更新 更多