2012-12-27 6 views
26

Sto provando a passare un oggetto tramite il servizio web REST. Di seguito sono le mie lezioni spiega la funzionalità di cui ho bisogno utilizzando alcuni codici di esempio.javax.xml.bind.JAXBException: Classe *** o qualsiasi sua super classe è nota in questo contesto

Resto Web Service Class metodo

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

Classe risposta

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

Dipartimento Classe

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

} 

Quando si effettua una chiamata al metodo getDepartments nella classe di servizio Web rest restituisce le seguenti eccezioni. Ma se cambio il tipo Oggetto del carico utile a Dipartimento nella classe di risposta restituisce correttamente la risposta JSON. Ma dal momento che ho bisogno di utilizzare questa classe di risposta per diversi tipi di classi non riesco a restringere il carico utile a un tipo di classe. Qualcuno può aiutarmi per favore in questa faccenda?

Stack Trace

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 
+5

si dovrebbe accettare la risposta fornita come funziona bene. – Daniel

+0

@Shanaka accetta una delle risposte fornite, #Bogdan la risposta è abbastanza buona. Scegli la migliore risposta e aiuta gli altri a scegliere saggiamente – Jeevanantham

risposta

49

JAX-RS implementazioni supportano automaticamente smistamento/unmarshalling di classi sulla base di individuabili annotazioni JAXB, ma perché il carico utile è dichiarato come Object, penso che il creato JAXBContext non trova la classe di Department e quando è il momento di ordinarlo, non sa come.

Una soluzione rapida e sporca sarebbe quello di aggiungere un'annotazione XmlSeeAlso alla classe risposta:

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

o qualcosa di un po 'più complicato sarebbe "arricchire" il contesto JAXB per la classe Response utilizzando un 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); 
    } 
} 
+1

Ho una lista di oggetti all'interno degli oggetti. Risolto dal tag '@ XmlSeeAlso'. Grazie! – Daniel

+1

non funziona per me :( – Anas

+0

Quando ho usato l'annotazione XmlSeeAlso, aggiungo queste informazioni al nodo: xmlns: xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi: type = "my_class" c'è un'opzione per rimuoverlo? –

5

Questa eccezione può essere risolto specificando il percorso completo della classe.

Esempio:

se siete classe denominata come ExceptionDetails.java


modo sbagliato di passaggio di argomenti

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

modo giusto di passaggio di argomenti

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

Molte grazie, Partha

+7

Sicuramente la specifica del pacchetto farebbe la differenza se avessi due versioni differenti di ExceptionDetails in diversi pacchetti e l'istruzione import stava usando quella "altra" ? – DarthPablo

2

Ho lo stesso problema e ho risolto con l'aggiunta di pacchetti per esplorare al Jaxb2marshaller. Per la primavera sarà definire un fagiolo come questo:

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

In questo modo, se tutte le classi di richiesta e di risposta sono nello stesso pacchetto non è necessario indicare specificamente le classi sulla JAXBContext

0

ho avuto un problema simile utilizzando l'implementazione di riferimento JAXB e JBoss AS 7.1. Sono stato in grado di scrivere un test di integrazione che ha confermato che JAXB funzionava al di fuori dell'ambiente JBoss (suggerendo che il problema potrebbe essere il caricatore di classi in JBoss).

Questo è il codice che stava dando l'errore (vale a dire che non funziona):

private static final JAXBContext JC; 

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

e questo è il codice che ha funzionato (ValueSet è una delle classi marshalling dal mio 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); 
    } 
} 

In alcuni casi, ho ricevuto la Classe, né una delle sue super classi è nota in questo contesto. In altri casi ho anche ottenuto un'eccezione di org.foo.bar.ValueSet non può essere lanciato su org.foo.bar.ValueSet (simile al problema descritto qui: ClassCastException when casting to the same class).