在泛型方法中传递类型时,使用TypeReference的ObjectMapper无法正常工作 [英] ObjectMapper using TypeReference not working when passed type in generic method

查看:985
本文介绍了在泛型方法中传递类型时,使用TypeReference的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是:

TestPageResult is:

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类型进行硬编码,那么我会得到正确的结果.

The resulting pageResult.getItems() contains a List of LinkedHashMap instead of a list of SomeDto. If I were to just hardcode the SomeDto type in the objectMapper.readValue method I'd get the correct results.

出什么问题了?

建议的重复确实解决了我的问题-一种. 我用过:

edit: The suggested duplicated did solve my problem - kind of. I used:

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

问题是没有解决方法,没有将Class参数传递给方法.因此,由于传递了泛型类型和与Class相同的东西,因此该方法看起来很难看.显然,您现在不能通过泛型,但是这种方式将需要强制转换并添加SuppressWarnings等.

Problem is there is no going around not passing down a Class argument to the method. So the method looks ugly due to both passing a generic type and the same thing as a Class. Obviously you can just not pass the generic now but this way a casting would be required and adding SuppressWarnings and so on.

推荐答案

问题是擦除.在擦除它们后,所有这些<T>参数在编译后的代码中都不存在.这意味着源new TypeReference<TestPageResult<T>>()一旦编译就看起来像new TypeReference<TestPageResult>(),这不是您想要的. (类似于List<String>在编译后的代码中最终成为List的方式,只是编译时验证,您没有在String List中添加Integer.)

The problem is erasure. All these <T> parameters don't exist in the compiled code, after they're erased. This means that source new TypeReference<TestPageResult<T>>() looks like new TypeReference<TestPageResult>() once compiled, which is not what you want. (Similar to how a List<String> ends up being a List in compiled code, and it's just compile-time validation that you don't add Integers to your String List.)

我认为(在这种情况下)大约有两种处理方式,您已经偶然发现了这两种方式:

I think there's roughly two ways to deal with this (in this case), both of these you already stumbled upon:

  • 要么创建一种可以正确表示所需内容的类型,例如:new TypeReference<TestPageResult<SomeDto>>()class SomeDtoPageResult extends TestPageResult<SomeDto>,然后就可以在诸如readValue(..., SomeDtoPageResult.class);
  • 之类的地方使用它们.
  • 或者您可以像使用JavaType
  • 一样创建完整的类表示形式
  • Either you create a type that properly represents what you want, such as: new TypeReference<TestPageResult<SomeDto>>(), or class SomeDtoPageResult extends TestPageResult<SomeDto> which you can then use in places like readValue(..., SomeDtoPageResult.class);
  • Or you create a complete class representation, like you were doing with JavaType

您真正想要的东西行不通.最好的选择是修补并提出解决该问题的最简洁的代码.泛型可以让您表达真正精巧的结构,当您序列化一个实际实例(嵌套对象)时,这种效果就很好了,但是当需要在运行时对这些类进行自检时,例如对于反序列化(您的用例)或构建模型(例如,生成Swagger文档),这将成为问题.

What you really want won't work. Your best bet is to tinker and come up with the cleanest code that solves it. Generics let you express really elaborate structures, and when you serialize an actual instance (nested objects), that comes out just fine, but when the classes need to be introspected at runtime, e.g. for deserialization (your use case) or to build a model (e.g. to generate Swagger docs), this becomes problematic.

这篇关于在泛型方法中传递类型时,使用TypeReference的ObjectMapper无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆