java - 无法以 XML 格式编码 REST

标签 java xml rest

我有一个 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 不知道 RestResponsecontent 或内容所依赖的其他一些类,例如 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/

相关文章:

java - Struts2 正则表达式验证负数问题

xml - 在应用任何其他模板之前,如何将完整文档转换为小写?

rest - 正确的 REST URL 格式

java - JAX-RS + JAXB (XML) -- 如何将单个字节作为十六进制传递?

javascript - 如何使用 PayPal Express Checkout 集成(客户端 REST)获取交易 ID

android - 如何在 Parse.com Rest Api 请求上使用 Client Key 而不是 Android 的 Rest Api Key

java - java中的Map返回引用

java - 如何使用 ExpectedException 规则在一个测试中测试多个异常?

java - 将所有请求重定向到 Wicket 中的特定页面

android - 我应该实现哪个库来使用应用程序 :layout_behavior ="@string/appbar_scrolling_view_behavior"