在泛型方法中传递类型时,使用 TypeReference 的 ObjectMapper 不起作用

ObjectMapper using TypeReference not working when passed type in generic method

这是方法:

protected <T> TestPageResult<T> getTestPageResutForRequest(MockHttpServletRequestBuilder request) throws Exception {
    String responseJson = mockMvc.perform(request).andReturn().getResponse()
            .getContentAsString();

    TestPageResult<T> response = getObjectMapper().readValue(responseJson,
            new TypeReference<TestPageResult<T>>() {
            });

    return response;
}

我这样称呼它:

 TestPageResult<SomeDto> pageResult = this.<SomeDto>getTestPageResutForRequest(getRequest());

测试页面结果为:

protected static class TestPageResult<T> {
    private List<T> items;
    private long totalCount = -1;

    public TestPageResult() {

    }
    //omitted getters and setters

}

生成的 pageResult.getItems() 包含一个 LinkedHashMap 列表,而不是一个 SomeDto 列表。如果我只是在 objectMapper.readValue 方法中硬编码 SomeDto 类型,我会得到正确的结果。

有什么问题?

编辑:建议的重复确实解决了我的问题 - 有点。 我用过:

JavaType type = getObjectMapper().getTypeFactory().constructParametricType(TestPageResult.class, clazz);
TestPageResult<T> response = getObjectMapper().readValue(responseJson, type);

问题是没有办法不向方法传递 Class 参数。因此该方法看起来很难看,因为它既传递了泛型类型又传递了与 Class 相同的东西。显然你现在不能通过泛型,但这样就需要转换并添加 SuppressWarnings 等等。

问题是擦除。所有这些 <T> 参数在被 擦除 之后都不存在于编译代码中。这意味着 source new TypeReference<TestPageResult<T>>() 编译后看起来像 new TypeReference<TestPageResult>(),这不是您想要的。 (类似于 List<String> 如何在编译代码中最终成为 List,这只是 compile-time 验证您没有将 Integer 添加到 String List.)

我认为大致有两种方法可以解决这个问题(在本例中),您已经偶然发现了这两种方法:

  • 您可以创建一个可以正确表示您想要的类型,例如:new TypeReference<TestPageResult<SomeDto>>(),或者 class SomeDtoPageResult extends TestPageResult<SomeDto>,然后您可以在 readValue(..., SomeDtoPageResult.class);[=35= 等地方使用它]
  • 或者您创建一个完整的 class 表示,就像您对 JavaType
  • 所做的那样

你真正想要的是行不通的。你最好的选择是修补并提出解决它的最干净的代码。泛型让你表达非常复杂的结构,当你序列化一个实际的实例(嵌套对象)时,结果很好,但是当 classes 需要在运行时进行自省时,例如对于反序列化(您的用例)或构建模型(例如生成 Swagger 文档),这会成为问题。