在Spring MVC控制器中反序列化单属性JSON有效负载

时间:2015-10-20 10:24:14

标签: json spring-mvc jackson

我想创建语义上类似于以下

的控制器方法
public HttpEntity<?> deleteUser(String userId){
...
}

客户端将传递用户ID作为JSON有效负载的一部分。如果我尝试注释@RequestBody字符串参数并发出{"userId":"foo"}有效负载,那么我会得到一个异常

Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token
 at [Source: java.io.PushbackInputStream@7311a203; line: 1, column: 1]
    at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148) ~[jackson-databind-2.6.1.jar:2.6.1]
    at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:854) ~[jackson-databind-2.6.1.jar:2.6.1]
    at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:62) ~[jackson-databind-2.6.1.jar:2.6.1]
    at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:11) ~[jackson-databind-2.6.1.jar:2.6.1]
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3702) ~[jackson-databind-2.6.1.jar:2.6.1]
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2798) ~[jackson-databind-2.6.1.jar:2.6.1]
    at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:221) ~[spring-web-4.2.0.RELEASE.jar:4.2.0.RELEASE]

这是合理的,因为JSON想要将复杂对象(即一个属性)反序列化为String

我也知道"foo"无效JSON。我知道我可以使用Map<String,Object>甚至更好ModelMap,作为最后的手段,我可​​以使用查询字符串和@RequestParam今天我的老板明确要求我找到一种方法来使用普通字符串而不是对象,以使代码看起来更具可读性。

如何强制Jackson / MVC仅反序列化用户名&#34;属性为普通的String

1 个答案:

答案 0 :(得分:1)

当Spring MVC找到与URL路径匹配的请求映射但参数(或标题或某些内容)与处理程序方法所期望的不匹配时,您通常会看到此类错误。

如果使用@RequestBody注释,则Spring MVC期望将POST请求的整个主体映射到Object,默认情况下它不适用于String。

如下所示,有不同的方法:

1)将deleteUser()方法类型的方法类型更改为GET而不是Post,并将userId更改为String。

2)你可以简单地将HttpServletRequest注入你的方法并阅读正文:

public void deleteUser(HttpServletRequest request) {
  String userID = IOUtils.toString( request.getInputStream());
  // do stuff
} 

3)使用可以替换String参数的包装器(JSON对象的java模型),这也适用于你帖子中的json。

public class UserWrapper {

    private String userId;
    //getter setters

然后在您的控制器中使用:

public void deleteUser(@RequestBody UserWrapper user) {
//do your stuff
}

4) Spring提供了一种配置多个消息转换器的方法,如下所示: 注意:然后,对各种方法的请求必须指定具有适当值的“content-type”标头。对于请求主体映射到JAXB bean的那些方法,请指定“application / xml”。对于请求体是String的那些,请使用“text / plain”。

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="messageConverters">
        <list>
            <ref bean="jsonConverter" />
            <ref bean="marshallingConverter" />
            <ref bean="stringHttpMessageConverter" />
        </list>
    </property>
</bean>

<bean id="jsonConverter"
      class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
    <property name="supportedMediaTypes" value="application/json" />
</bean>

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

<bean id="stringHttpMessageConverter"
      class="org.springframework.http.converter.StringHttpMessageConverter">
    <property name="supportedMediaTypes" value="text/plain"/>
</bean>

希望这对你有帮助!