我正在尝试通过REST Web服务传递对象。以下是我的课程使用一些示例代码解释了我需要的功能。
Rest Web Service Class方法
@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类中将有效负载的类型对象更改为部门,则会正确返回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
答案 0 :(得分:58)
JAX-RS实现自动支持基于可发现的JAXB注释的类的编组/解组,但由于您的有效负载被声明为Object
,我认为创建的JAXBContext
错过了Department
类什么时候发动它不知道怎么做。
快速而肮脏的修复方法是在响应类中添加XmlSeeAlso
注释:
@XmlRootElement
@XmlSeeAlso({Department.class})
public class Response implements Serializable {
....
或者更复杂的东西是“通过Response
来丰富”ContextResolver
类的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);
}
}
答案 1 :(得分:5)
我有同样的问题,我通过添加包来探索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上专门指出类
答案 2 :(得分:4)
可以通过指定完整的类路径来解决此异常。
示例:强>
如果您使用的是名为ExceptionDetails
传递参数的方法错误
JAXBContext jaxbContext = JAXBContext.newInstance(ExceptionDetails.class);
传递参数的正确方法
JAXBContext jaxbContext = JAXBContext.newInstance(com.tibco.schemas.exception.ExceptionDetails.class);
答案 3 :(得分:1)
我在使用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)。
答案 4 :(得分:1)
在支持一个应用程序时,我遇到了类似的错误。这与为SOAP Web服务生成的类有关。
此问题是由于缺少类引起的。当javax.xml.bind.Marshaller试图封送jaxb对象时,它没有找到由wsdl和xsd生成的所有依赖类。在将class包含所有类的jar添加到类路径后,问题得以解决。
答案 5 :(得分:1)
就像@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]);
}
答案 6 :(得分:0)
Ftrujillo's answer效果很好,但是如果您只有一个要扫描的软件包,这是最短的形式:
@Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("your.package.to.scan");
return marshaller;
}
答案 7 :(得分:0)
我知道这是一个老问题,但是您可以使用参数(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 :(得分:0)
当我们对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;
}
即使是不同的类别,您也应该使用不同的名称