views:

66

answers:

1

Here is my situation:

I have my mvc-config.xml file for my web service set up to have JSON as the default media type. I also have favorParameter for the ContentNegotiatingViewResolver as true. Additionally, I have useNotAcceptableStatusCode as true so that not accepted formats will return a 406.

My question is: Is there a way, in the config, to trigger the 406 status code when someone passes in an unacceptable format parameter (format=foo)? Or must that be done with code?

Here is the config file:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"&gt;

    <bean
        class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
        <property name="mediaTypes">
            <map>
                <entry key="json" value="application/json" />
                <entry key="xml" value="application/xml" />
            </map>
        </property>
        <property name="defaultViews">
            <list>
                <bean class="com.work.stuff.web.view.json.ExtendedMappingJacksonJsonView">
                    <property name="objectMapper">
                        <ref bean="JacksonObjectMapper" />
                    </property>
                </bean>
                <bean class="org.springframework.web.servlet.view.xml.MarshallingView">
                    <property name="marshaller">
                        <ref bean="Jaxb2Marshaller" />
                    </property>
                </bean>
            </list>
        </property>
        <property name="defaultContentType" value="application/json" />
        <property name="favorParameter" value="true" />
        <property name="useNotAcceptableStatusCode" value="true" />
    </bean>

    <bean
        class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="messageConverters">
            <list>
                <bean
                    class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
                    <property name="objectMapper">
                        <ref bean="JacksonObjectMapper" />
                    </property>
                </bean>
                <ref bean="marshallingHttpMessageConverter" />
            </list>
        </property>
    </bean>

    <bean id="marshallingHttpMessageConverter"
        class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
        <property name="marshaller" ref="Jaxb2Marshaller" />
        <property name="unmarshaller" ref="Jaxb2Marshaller" />
    </bean>
    <bean id="JacksonObjectMapper" class="org.codehaus.jackson.map.ObjectMapper" />
    <bean id="JacksonSerializationConfig" class="org.codehaus.jackson.map.SerializationConfig"
        factory-bean="JacksonObjectMapper" factory-method="getSerializationConfig" />
    <bean
        class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="targetObject" ref="JacksonSerializationConfig" />
        <property name="targetMethod" value="setSerializationInclusion" />
        <property name="arguments">
            <list>
                <value type="org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion">NON_NULL</value>
            </list>
        </property>
    </bean>
    <bean id="Jaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
        <property name="classesToBeBound">
            <list>
                <value>com.work.stuff.Concepts</value>
                <value>com.work.stuff.Concept</value>
                <value>com.work.stuff.Terms</value>
                <value>com.work.stuff.Term</value>
                <value>com.work.stuff.Namespaces</value>
                <value>com.work.stuff.Namespace</value>
                <value>com.work.stuff.Subsets</value>
                <value>com.work.stuff.Subset</value>
                <value>com.work.stuff.Associations</value>
                <value>com.work.stuff.Association</value>
            </list>
        </property>
    </bean>
</beans>
+3  A: 

ContentNegotiatingViewResolver doesn't seem to support such behaviour. For now, I think your best bet is to subclass it and override the getMediaTypeFromParameter() method to throw an exception if the media type is not supported.

You can throw any RuntimeException from that method, and if you annotate the exception class with @ResponseStatus, you can control the HTTP response code, e.g.

@ResponseStatus(HttpStatus.NOT_ACCEPTABLE)
public class FormatNotSupportedException extends RuntimeException {
}

In the longer term, I strongly encourage you to file an issue with http://jira.springsource.org, asking for such functionality to be added to ContentNegotiatingViewResolver. They should be able to add this as an optional behavioural parameter. It's requests like these that mean Spring keeps getting better.

skaffman
Thank you very much. I will file an issue (and accept and up vote when time limits come off).
AHungerArtist