使用@RequestBody List <! - ? - >的Spring MVC REST在语法上返回HTTP 400不正确

时间:2015-05-31 14:21:50

标签: rest spring-mvc jackson

我正在使用Spring 4 + Jackson 2,并在自定义类上使用@RequestBody编写了一个功能齐全的POST方法。这种方法可以解组对象。

@ResponseBody
@RequestMapping(value="store", method = RequestMethod.POST)
public ServiceResponse store(@RequestBody CustomClass list) {
    ...
}

// Request: { code: "A", amount: 200 }

当我尝试添加另一个方法来处理同一个类的集合时,我的POST请求返回时出现以下错误。

  

HTTP状态400:客户端发送的请求在语法上不正确。

我注意到,当提交的JSON与实体类不匹配时,通常会发生此错误。但是,我所做的只是提交一个相同对象的数组而不是对象本身,这已被证明有效。

@ResponseBody
@RequestMapping(value="store-bulk", method = RequestMethod.POST)
public ServiceResponse storeBulk(@RequestBody List<CustomClass> list) {
    ...
}

// Request: [{ code: "A", amount: 200 }, { code: "B", amount: 400 }]

我在这里错过了什么吗?

3 个答案:

答案 0 :(得分:0)

在Java中,泛型的类型信息在运行时被删除,因此Spring将List<CustomClass> object视为List<Object> object,因此无法理解如何解析它。

解决问题的方法之一是,您可以通过为列表创建包装类来捕获类型信息,如下所示:

public class CustomClassList extends ArrayList<CustomClass> {
}

答案 1 :(得分:0)

谢尔盖是对的,问题是由于类型擦除。最简单的方法是绑定到一个数组,所以

@ResponseBody
@RequestMapping(value="store-bulk", method = RequestMethod.POST)
public ServiceResponse storeBulk(@RequestBody CustomClass[] object) {
    ...
}

答案 2 :(得分:0)

答案是Spring 4并没有真正摆脱类型擦除,这与其他一些解决方案所暗示的相反。在通过手动解组进行调试的同时,我决定自己处理这个步骤,而不是我无法控制的隐式转换。我确实希望有人出现并证明我错了,尽管展示了更直观的解决方案。

@ResponseBody
@RequestMapping(value="store-bulk", method = RequestMethod.POST)
public ServiceResponse storeBulk(@RequestBody String json) {
    try {
        List<CustomClass> list = new ObjectMapper().readValue(json, new TypeReference<List<CustomClass>>() { });
        ...
    } catch (Exception e) {
        ...
    }
}

奖金:在我开始工作之后,我碰到了这个例外:

  

IllegalStateException:已经有id的POJO

如果有人得到这个,那就是因为列表中的对象碰巧引用了列表中另一个项已经引用的某个对象。我可以解决这个问题,因为该对象对于我的整个集合来说都是相同的,所以我只是从第一个对象中删除了JSON端的引用。然后,在JSON被解组到List对象之后,我又添加了缺少的引用。

Java 8用户的双线程(用户对象引用是我的问题):

User user = list.get(0).getUser();
list.stream().filter(c -> c.getUser() == null).forEach(t -> t.setUser(user));