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

时间:2018-02-15 10:06:49

标签: java unit-testing generics jackson objectmapper

这是方法:

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());

TestPageResult是:

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

    public TestPageResult() {

    }
    //omitted getters and setters

}

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

有什么问题?

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

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

问题是没有将没有传递给方法的Class参数。因此,由于传递泛型类型和类相同,因此该方法看起来很丑陋。显然你现在不能传递通用,但这样就需要一个连接并添加SuppressWarnings等等。

1 个答案:

答案 0 :(得分:0)

问题是擦除。所有这些<T>参数在被删除之后不会存在于已编译的代码中。这意味着源new TypeReference<TestPageResult<T>>()在编译后看起来像new TypeReference<TestPageResult>(),这不是您想要的。 (类似于List<String>在编译代码中最终成为List的方式,而且只是编译时验证,您不会将Integer添加到您的String List。)

我认为有两种方法可以解决这个问题(在这种情况下),你已经偶然发现了这两种方法:

  • 您可以创建一个正确代表您想要的内容的类型,例如:new TypeReference<TestPageResult<SomeDto>>()class SomeDtoPageResult extends TestPageResult<SomeDto>,然后您可以在readValue(..., SomeDtoPageResult.class)等地方使用这些类型;
  • 或者您创建了一个完整的类表示,就像您使用JavaType
  • 一样

你真正想要的是什么。你最好的办法是修补并提出解决它的最干净的代码。泛型允许你表达非常精细的结构,当你序列化一个实际的实例(嵌套对象)时,它就会很好,但是当需要在运行时对类进行内省时,例如对于反序列化(您的用例)或构建模型(例如生成Swagger文档),这就成了问题。