我有一个 GET 端点,它可以返回 JSON 和 XML 格式:
@RequestMapping(method = RequestMethod.GET, produces = {"application/json", "application/xml" })
@ResponseBody
public Object getV6Subnet(@RequestBody V6SubnetRequest requestBody){
RestResponse<V6SUBNETREC> response = null;
V6SUBNETREC wsSubnet = null;
// do something to set value for wsSubnet
response = RESTfulUtil.buildSuccessResponse(wsSubnet);
return response;
}
我的 RESTfulUtil 类:
public class RESTfulUtil {
public synchronized static RestResponse buildSuccessResponse(Object content){
RestResponse response = new RestResponse();
response.setContent(content);
return response;
}
}
休息响应
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name="RestResponse")
@XmlSeeAlso({
ErrorResponse.class,
V6SUBNETREC.class,
V4ADDRREC.class,
V4SUBNETREC.class,
LOCATIONREC.class,
CONTACTREC.class,
})
public class RestResponse<T> extends SimpleRestResponse {
@XmlElement
private T content;
public T getContent() {
return content;
}
public void setContent(T content) {
this.content = content;
}
}
还有我的 SimpleRestResponse 类:
public class SimpleRestResponse {
private int code;
private int httpStatusCode;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
@JsonIgnore
public int getHttpStatusCode() {
return httpStatusCode;
}
public void setHttpStatusCode(int httpStatusCode) {
this.httpStatusCode = httpStatusCode;
}
}
当我请求 JSON 格式时,我得到:
{"code":21,"content":{"error":"Subnet not found."}}
但是当我请求 XML 格式时,出现错误:
Could not marshal [ws.restful.model.RestResponse@56b97914]: null; nested exception is javax.xml.bind.MarshalException
org.springframework.http.converter.HttpMessageNotWritableException: Could not marshal [com.lucent.qip.nb.ws.restful.model.RestResponse@56b97914]: null; nested exception is javax.xml.bind.MarshalException
- with linked exception:
[com.sun.istack.SAXException2: class com.lucent.qip.nb.ws.restful.model.ErrorResponse nor any of its super class is known to this context.
javax.xml.bind.JAXBException: class com.lucent.qip.nb.ws.restful.model.ErrorResponse nor any of its super class is known to this context.]
org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter.writeToResult(Jaxb2RootElementHttpMessageConverter.java:184)
org.springframework.http.converter.xml.AbstractXmlHttpMessageConverter.writeInternal(AbstractXmlHttpMessageConverter.java:66)
org.springframework.http.converter.AbstractHttpMessageConverter.write(AbstractHttpMessageConverter.java:208)
org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:161)
org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:101)
org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:185)
org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:71)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:126)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:776)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:705)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967)
org.springframework.web.servlet.FrameworkServlet.doDelete(FrameworkServlet.java:891)
javax.servlet.http.HttpServlet.service(HttpServlet.java:652)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843)
javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.springframework.orm.hibernate4.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:151)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
com.lucent.qip.utils.filters.ResponseHeaderFilter.doFilter(ResponseHeaderFilter.java:60)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)
org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
com.lucent.qip.nb.ws.restful.security.AuthenticationTokenProcessingFilter.doFilter(AuthenticationTokenProcessingFilter.java:55)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
我无法显示我的 web.xml 和 applicationContext.xml 我只能提供rest-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven content-negotiation-manager="contentNegotiationManager" />
<interceptors>
<interceptor>
<mapping path="/openstack" />
<beans:bean
class="com.lucent.qip.nb.ws.restful.controller.OpenStackController"></beans:bean>
</interceptor>
</interceptors>
<!-- for processing requests with annotated controller methods and set Message
Convertors from the list of convertors -->
<beans:bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<beans:property name="messageConverters">
<beans:list>
<beans:ref bean="jsonMessageConverter" />
<beans:ref bean="xmlConverter" />
</beans:list>
</beans:property>
</beans:bean>
<!-- To convert JSON to Object and vice versa -->
<beans:bean id="jsonMessageConverter"
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
<!-- To convert XML to Object and vice versa -->
<beans:bean id="xmlConverter"
class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<beans:constructor-arg ref="jaxbMarshaller" />
<beans:property name="supportedMediaTypes" value="application/xml" />
</beans:bean>
<!-- JAXB Classes to be marshalled -->
<beans:bean id="jaxbMarshaller"
class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<beans:property name="packagesToScan">
<beans:list>
<beans:value>com.lucent.qip.nb.ws.restful.model</beans:value>
</beans:list>
</beans:property>
</beans:bean>
<beans:bean id="JacksonObjectMapper" class="com.fasterxml.jackson.databind.ObjectMapper" />
<beans:bean id="contentNegotiationManager"
class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<beans:property name="favorPathExtension" value="true" />
<beans:property name="ignoreAcceptHeader" value="true" />
<beans:property name="defaultContentType" value="application/json" />
<beans:property name="useJaf" value="false" />
<beans:property name="mediaTypes">
<beans:map>
<beans:entry key="json" value="application/json" />
<beans:entry key="xml" value="application/xml" />
</beans:map>
</beans:property>
</beans:bean>
<context:component-scan base-package="com.lucent.qip.nb.ws.restful.controller" />
</beans:beans>
我还为所有类 V6SUBNETREC、V4ADDRREC、ErrorResponse 添加了 @XmlRootElement, V4SUBNETREC、LOCATIONREC、CONTACTREC也没有解决
最佳答案
问题是当前线程的 JAXBContext 不知道 RestResponse
的 content
或内容所依赖的其他一些类,例如 ErrorResponse
(来自你的堆栈跟踪)。要解决此问题,您可以将所需的类引入 JAXBContext,如下所示。
首先注释所有需要转换为xml的类都应该用@XmlRootElement
注释
然后为 Spring 的 HttpMessageConvertors 添加以下 bean 配置。假设您使用注释驱动:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(marshallingMessageConverter());
}
@Bean
public MarshallingHttpMessageConverter marshallingMessageConverter() {
MarshallingHttpMessageConverter converter = new MarshallingHttpMessageConverter();
converter.setMarshaller(jaxbMarshaller());
converter.setUnmarshaller(jaxbMarshaller());
return converter;
}
@Bean
public Jaxb2Marshaller jaxbMarshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setPackagesToScan("com.lucent.qip.nb.ws.restful.model");//you need to specify the package where your @XmlRootElement s reside
Map<String, Object> props = new HashMap<String, Object>();
props.put(javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setMarshallerProperties(props);
return marshaller;
}
}
你可以看到上面代码中的内嵌注释,我指定了需要包含在JAXBcontext中的类的包。 需要的maven依赖是:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${spring.version}</version>
</dependency>
我已经使用 4.1.5.RELEASE 进行了测试
关于java - 无法以 XML 格式编码 REST,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34081154/