Announcement Announcement Module
Collapse
No announcement yet.
JSON HttpMediaTypeNotSupportedException Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • JSON HttpMediaTypeNotSupportedException

    I'm getting an exception when sending JSON over to a Spring Annotated Controller. I believe the problem is related to converting a JSON into a RequestBody. I am unable to switch to full MVC Annotations - I have to use SimpleUrlHandlerMapping for now

    Code:
    2010-02-15 16:59:53,437 ERROR [ingExceptionResolver][TP-Processor2       ] Error thrown while executing request
    org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/json;charset=UTF-8' not supported
    	at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveRequestBody(HandlerMethodInvoker.java:556)
    	at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveHandlerArguments(HandlerMethodInvoker.java:283)
    	at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:163)
    	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:414)
    	at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:402)
    	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:771)
    	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:716)
    	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:647)
    	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:563)
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
    This is the form + javascript modified from mvc-ajax sample

    http://blog.springsource.com/2010/01...in-spring-3-0/

    Code:
    	<form:form id="createUser" modelAttribute="user" method="post">
    	  	<fieldset>		
    			<legend>User Fields</legend>
    			<p>
    				<form:label	id="nameLabel" for="name" path="username" cssErrorClass="error">Name</form:label><br/>
    				<form:input path="username" /><form:errors path="name" />
    				<form:label id="idLabel" for="id" path="id" cssErrorClass="error">Id</form:label><br/>
    				<form:input path="id" /><form:errors path="id" />
    			</p>
    			<p>	
    				<input id="create" type="submit" value="Create" />
    			</p>
    		</fieldset>
    	</form:form>
    	<script type="text/javascript">	
    		$(document).ready(function() {
    			$("#createUser").submit(function() {
    				var user = $(this).serializeObject();
    				$.postJSON("user", user, function(data) {
    					$("#id").val(data.id);
    					alert("got response");
    				});
    				return false;				
    			});
    		});
    	</script>
    This is a snippet of the server side code:

    Code:
    @Controller(value="accountsController")
    public class AccountController {
     ....
        @RequestMapping(method=RequestMethod.POST)
        public @ResponseBody Map<String, ? extends Object> create(@RequestBody User user, HttpServletResponse response) {
            return Collections.singletonMap("id", user.getId());
        }
    }
    I had a problem using <mvc:annotation-driven/> on it's own, I read somewhere that I need to declare SimpleControllerHandlerAdapter as well.

    Code:
        <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
            <property name="mappings">
                <props>
                    ....
    		<prop key="/accounts/**/*">accountsController</prop>
                    ....
                </props>
            </property>
            <property name="alwaysUseFullPath" value="true"/>
        </bean>
    
        <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
        <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
        <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        	<property name="messageConverters">
          	<util:list id="beanList">
    	        <bean id="stringHttpMessageConverter" class="org.springframework.http.converter.StringHttpMessageConverter"/>
    	        <bean id="formHttpMessageConverter" class="org.springframework.http.converter.FormHttpMessageConverter"/>
    	        <bean id="byteArrayMessageConverter" class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
    	        <bean id="bufferedImageHttpMessageConverter" class="org.springframework.http.converter.BufferedImageHttpMessageConverter"/>
    	        <bean id="jacksonMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
          	</util:list>
        	</property>
    	</bean>
    Any help would be appreciated

    Thanks

  • #2
    The problem I believe was that the server side (User) Object was not serializable (legacy object with lots more properties than necessary - one or more of which must be not serializable). I just switched an simple object and json conversion worked fine.

    Comment


    • #3
      For anyone reading this thread. Test your objects to make sure they are serializable and deserializable. In the case of Jackson, the MappingJacksonHttpMessageConverter does not throw an exception or log anything. It simply uses the method canRead(Class<?>, MediaType) to check if the data can be deserialized into an object. If it cannot, it just moves on....

      Comment


      • #4
        Poor jackson error handling

        To expand on this even further, you cannot have any configuration errors with your Jackson annotations. In my case, I had multiple @JsonBackReference in a domain object and it was throwing an error (they must have unique names) but trapping it without logging:

        org.codehaus.jackson.map.deser.StdDeserializerProv ider
        Code:
            public boolean hasValueDeserializerFor(DeserializationConfig config, JavaType type)
            {
                /* Note: mostly copied from findValueDeserializer, except for
                 * handling of unknown types
                 */
                JsonDeserializer<Object> deser = _findCachedDeserializer(type);
                if (deser == null) {
                    try {
                        deser = _createAndCacheValueDeserializer(config, type, null);
                    } catch (Exception e) {
                        return false;
                    }
                }
                return (deser != null);
            }

        Comment


        • #5
          Originally posted by mcantrell View Post
          To expand on this even further, you cannot have any configuration errors with your Jackson annotations. In my case, I had multiple @JsonBackReference in a domain object and it was throwing an error (they must have unique names) but trapping it without logging:
          Hi mcantrell, I also have the problem with multiple @JsonBackReference in a domain object. For example, my CdrDoseFrequency will have relationship Many-To-One to CdrInfusionDrug and CdrNormalDrug, so my code is follow:
          Code:
          @JsonBackReference("CdrInfusionDrug")
          public CdrInfusionDrug getCdrInfusionDrug() {}
          
          @JsonBackReference("CdrNormalDrug")
          public CdrNormalDrug getCdrNormalDrug() {}
          Then when I run spring restful, I have the error: 415: Unsupported Media Type. Could you please give me advice for this case ?

          Comment


          • #6
            I just stumbled upon this, and in my case the problem was an overloaded setter method. I.e. I had a String property with 2 setters, the standard one that accepts a String and another one that accepts a BigDecimal. Jackson will get confused by this and will not deserialize your JSON resulting in the infamous HttpMediaTypeNotSupportedException.

            How to fix: several ways:
            1. I'm lazy so I just renamed the "unstandard" setters.
            2. Use jackson's annotations (or jaxb annotations if you have this enabled).
            3. Add a mixin to your deserializer telling it to ignore the "unstandard" setter.

            Hope this info is useful.

            Comment

            Working...
            X