Подтвердить что ты не робот

Javax.xml.bind.JAXBException: класс ***, ни один из его суперклассов не известен этому контексту

Я пытаюсь передать объект через веб-службу REST. Ниже приведены мои классы, объясняющие функциональность, которая мне нужна, с использованием некоторых примеров кодов.

Метод класса веб-службы останова

@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;
    }

}

Когда я вызываю метод getDepartments в классе остальных веб-сервисов, он возвращает следующие исключения. Но если я изменил тип Объект полезной нагрузки на Департамент в классе Response, он правильно вернет ответ 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
4b9b3361

Ответ 1

Реализации JAX-RS автоматически поддерживают сортировку/разборку классов на основе обнаруженных JAXB-аннотаций, но поскольку ваша полезная нагрузка объявлена ​​как Object, я думаю, что созданный JAXBContext пропускает класс Department и когда он время для marshall он не знает, как это сделать.

Быстрое и грязное исправление заключалось бы в добавлении аннотации XmlSeeAlso к вашему классу ответов:

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

или что-то более сложное было бы "обогатить" контекст JAXB для класса Response, используя ContextResolver:

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);
    }
}

Ответ 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);

Ответ 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);
    }
}

В некоторых случаях я получил класс, и ни один из его суперкласса не известен этому контексту. В других случаях я также получил исключение из org.foo.bar.ValueSet не может быть передан в org.foo.bar.ValueSet(аналогично описанной здесь проблеме: ClassCastException при литье в тот же класс).

Ответ 5

Я сталкивался с подобной ошибкой при поддержке одного приложения. Речь шла о сгенерированных классах для SOAP Webservice.

Проблема была вызвана отсутствующими классами. Когда javax.xml.bind.Marshaller пытался упорядочить объект jaxb, он не находил все зависимые классы, после которых генерировались wsdl и xsd. после добавления jar со всеми классами в пути к классам проблема была решена.

Ответ 6

Ответ Ftrujillo работает хорошо, но если у вас есть только один пакет для сканирования, это самая короткая форма:

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

Ответ 7

Я знаю, что это старый вопрос, но вы можете изменить ответ, используя параметр (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>}

Ответ 8

Эта ошибка возникает, когда мы используем то же имя метода для 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;
    }

Даже если это другой класс, вы должны называть их по-разному