Spring+BlazeDS+REST XML response

438 views Asked by At

Server is returning 406 HTTP Code when XML but working fine in case of JSON. Following are the code snippets and attached logs as well:

Libraries:

BlazeDS 4.0, Spring 3.2, JBoss 7.1.1Final, Maven 3.0

REST MVC Controller:

@Controller
@RequestMapping("/contacts")
public class ContactsController {

    @RequestMapping(method = RequestMethod.GET,produces= {"application/xml","application/json"})
    @ResponseStatus(value=HttpStatus.OK)
    public @ResponseBody List<Contact> find(@RequestParam(required = false) String searchStr) {

Config Spring:

@Configuration
@EnableWebMvc
public class Config extends WebMvcConfigurerAdapter {

    @Override
    public void configureContentNegotiation(
            ContentNegotiationConfigurer configurer) {
        configurer.defaultContentType(MediaType.APPLICATION_XML)
                .mediaType("xml", MediaType.APPLICATION_XML)
                .mediaType("json", MediaType.APPLICATION_JSON);

        }
    }

Spring configuration

<context:component-scan base-package="com.heksa.services"
    use-default-filters="false">
    <context:include-filter expression="org.springframework.stereotype.Controller"
        type="annotation" />
</context:component-scan>
 <bean id="contentNegotiationManager"
    class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
    <property name="defaultContentType" value="application/xml" />

    <property name="mediaTypes">
        <map>
            <entry key="json" value="application/json" />
            <entry key="xml" value="application/xml" />
        </map>
    </property>
</bean>
<bean id="xmlViewer"
    class="org.springframework.web.servlet.view.xml.MarshallingView">
    <constructor-arg>
        <bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
            <property name="classesToBeBound">
                <list>
                    <value>com.heksa.bean.Contact</value>
                </list>
            </property>
        </bean>
    </constructor-arg>
</bean>
<mvc:annotation-driven
    content-negotiation-manager="contentNegotiationManager" />

<mvc:default-servlet-handler />

<!-- Flex-specific Configuration -->
<flex:message-broker mapping-order="1">
    <flex:mapping pattern="/messagebroker/*" />
    <flex:message-service
        default-channels="my-streaming-amf,my-longpolling-amf,my-polling-amf" />
    <flex:secured />
</flex:message-broker>

JBoss Logs:

14:13:06,228 INFO  [org.springframework.oxm.jaxb.Jaxb2Marshaller] (MSC service thread 1-8) Creating JAXBContext with classes to be bound [class com.heksa.bean.Contact]
14:13:06,241 INFO  [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping] (MSC service thread 1-8) Mapped "{[/contacts],methods=[GET],params=[],headers=[],consumes=[],produces=[application/xml || application/json],custom=[]}" onto public java.util.List<com.heksa.bean.Contact> com.heksa.services.ContactsController.find(java.lang.String)
14:13:06,241 INFO  [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping] (MSC service thread 1-8) Mapped "{[/contacts/{id}],methods=[DELETE],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public void com.heksa.services.ContactsController.delete(int)
14:13:06,242 INFO  [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping] (MSC service thread 1-8) Mapped "{[/contacts],methods=[POST],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public com.heksa.bean.Contact com.heksa.services.ContactsController.create(com.heksa.bean.Contact)
14:13:06,296 INFO  [org.springframework.web.servlet.handler.SimpleUrlHandlerMapping] (MSC service thread 1-8) Mapped URL path [/**] onto handler 'org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler#0'
2

There are 2 answers

2
axiopisty On

Problem

The problem described (it would be nice if the OP asked a question instead of just describe a problem) is one of content negotiation caused by a mismatch between the Accept header supplied by the client, and the Content-Type header supplied by the server.

Credible and/or Official Sources

The HTTP specification itself (RFC 2616) is both credible and official.

Section 14.1 describes the Accept header:

If no Accept header field is present, then it is assumed that the client accepts all media types. If an Accept header field is present, and if the server cannot send a response which is acceptable according to the combined Accept field value, then the server SHOULD send a 406 (not acceptable) response.

Section 14.17 describes the Content-Type header.

Solution

Since the application configures application/xml to be the default content type returned, if you want to get a response in xml you must either assert that no Accept header is specified in the HTTP request or assert the HTTP request contains the HTTP header

Accept: application/xml

Assert the HTTP response sent by the server contains the HTTP header

Content-type: application/xml; charset=utf-8

You can use a traffic sniffer to see exactly what is being sent across the wire. One popular tool for this is Wireshark.

0
Phani On

After adding the HttpMessageConverters like below in SpringConfiguration file it worked.

<bean class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
            <constructor-arg ref="jaxbMarshaller" />
            <property name="supportedMediaTypes" value="application/xml" />
</bean>

<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
    <property name="classesToBeBound">
        <list>
            <value>com.heksa.bean.Contact</value>
        </list>
    </property>
</bean>