【问题标题】:Spring + Jackson + Deserializing List of Generic ObjectsSpring + Jackson + 反序列化通用对象列表
【发布时间】:2014-03-11 16:18:17
【问题描述】:

我有以下控制器:

@RequestMapping(value = "/test/inst/", method = RequestMethod.POST)
public @ResponseBody ResponseDTO<InstDTO> 
        testPostREST(@RequestBody RequestDTO<InstDTO> instDTO) {

    RequestDTO<InstDTO> dto = new RequestDTO<InstDTO>();

    ResponseDTO<InstDTO> responseDto = new ResponseDTO<InstDTO>();
    responseDto.setPayload(instDTO.getPayload());
    return responseDto; 
}

使用以下请求对象:

@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
public class RequestDTO<T> {

    private List<T> payload;

    public RequestDTO() {
        System.out.println("constructor");
    }

    public RequestDTO(List<T> payload) {
        this.payload = payload;
    }

    public List<T> getPayload() {
        return payload;
    }

    public void setPayload(List<T> payload) {
        this.payload = payload;
    }
}

当 POST 通过并且我查看我得到的对象时,有效负载列表具有 LinkedHashMap 对象,而不是我的 DTO 类型的对象。

如何让 spring+jackson 将 JSON 转换为我的 DTO 对象。请记住,我计划将包装器 ResponseDTO 重用于其他对象列表,这就是我使用通用列表 (List) 的原因。

这是我正在尝试的 JSON。

{
  "payload": [
    {
      "d": "Test 0",
      "id": "abcde",
      "c": "Test 0"
    },
    {
      "d": "Test 1",
      "id": "123",
      "c": "Test 1"
    }
  ]
}

【问题讨论】:

  • 你使用的是哪个 Spring 版本?
  • 我相信这将在 Spring 3.1+ 中开箱即用。
  • 无法升级到 3.1 怎么办?我知道升级听起来微不足道,但这是我无法控制的。
  • 下面的答案似乎很合适。
  • 毕竟我能够进行升级。我必须升级到 Spring 3.2 才能工作,并将 Jackson 从 1.9.1 升级到 1.9.2。似乎现在可以工作了。

标签: java json spring rest jackson


【解决方案1】:

由于类型擦除,您的代码无法运行。 Jackson 运行时不知道您正在尝试将有效负载编组为 InstitutionDTO 对象(因为此信息在编译时已被删除)。当 Jackson 查看有效负载时,它会在网络上看到有效的 JSON 对象,并在 Java 端看到 List&lt;Object&gt;。它别无选择,只能将有效负载映射到Map 实现,在您的情况下似乎是LinkedHashMap

您可以通过以下方式实现您想要的:

class RequestDTO<T> {}
class ResponseDTO<T> {}
class InstitutionDTO {}
class InstitutionRequestDTO extends RequestDTO<InstitutionDTO>
class InstitutionResponseDTO extends ResponseDTO<InstitutionDTO>

@RequestMapping(value = "/test/institution/", method = RequestMethod.POST)
public @ResponseBody InstitutionResponseDTO
    testPostREST(@RequestBody InstitutionRequestDTO institutionDTO) { }

免责声明:我自己没有尝试过此代码,但我的大多数应用程序都有与此类似的代码,并且它可以与 Jackson、Castor、Atom 等一起使用而不会出现故障。

【讨论】:

  • 给定一个声明为method(List&lt;String&gt; whatever) 的方法,您可以获得List 的泛型类型参数。较新版本的 Spring 使用了这个。
  • 我的尝试是节省海报的升级工作。
  • 您的解决方案很好,但Your code does not work due to type erasure 的说法是正确的。
  • 谢谢两位。 @Sotirios 您能否详细说明您上面关于获取泛型类型参数的评论。
  • 我可以通过升级到 spring 3.2 来让它工作。但是,当我运行 JUnit 测试时,它的行为就像升级前一样。对可能发生的事情有任何想法吗?
【解决方案2】:

如果不需要使用 Jackson,那么您可能需要考虑使用 Gson。

你可以告诉 Gson 如何反序列化你的 json,只需要传递一个 json 字符串和你想要反序列化的类。这会很简单。我已经包含了一个示例,我必须在下面反序列化来自 rest api 的响应。

entity = response.getEntity();
jsonResponse = EntityUtils.toString(entity);
JsonNode root = mapper.readTree(jsonResponse).get("result");
returnedProduct = gson.fromJson(root.toString(),Product.class);

【讨论】:

  • 这个解决方案也可以用 Jackson 来实现。海报没有直接使用 Jackson,而是通过 Spring MVC。问题在于 Spring MVC 如何将数据传递给 Jackson。
猜你喜欢
  • 2022-01-22
  • 2021-06-03
  • 2018-11-17
  • 1970-01-01
  • 2019-10-25
  • 2023-03-13
  • 2020-08-07
  • 2021-02-18
  • 2018-05-09
相关资源
最近更新 更多