ObjectMapper using TypeReference not working when passed type in generic method

≯℡__Kan透↙ 提交于 2021-02-07 20:53:14

问题


This is the 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;
}

I call it like this:

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

TestPageResult is:

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

    public TestPageResult() {

    }
    //omitted getters and setters

}

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.

What's the problem?

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

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.


回答1:


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:

  • 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

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.



来源:https://stackoverflow.com/questions/48804508/objectmapper-using-typereference-not-working-when-passed-type-in-generic-method

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!