在具有泛型参数的泛型方法中使用Spring RestTemplate [英] Using Spring RestTemplate in generic method with generic parameter

查看:181
本文介绍了在具有泛型参数的泛型方法中使用Spring RestTemplate的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了在Spring RestTemplate中使用泛型类型,我们需要使用 ParameterizedTypeReference 无法获得泛型ResponseEntity< T>其中T是泛型类SomeClass< SomeGenericType>



假设我有一些课程

  public class MyClass {
int users [];

public int [] getUsers(){return users; }
public void setUsers(int [] users){this.users = users;}
}

以及一些包装类

  public class ResponseWrapper< T> {
T应答;

public T getResponse(){return response; }
public void setResponse(T response){this.response = response;}
}

所以如果我试图做这样的事情,一切都会好的。

  public ResponseWrapper< MyClass> makeRequest(URI uri){
ResponseEntity< ResponseWrapper< MyClass>> response = template.exchange(
uri,
HttpMethod.POST,
null,
new ParameterizedTypeReference< ResponseWrapper< MyClass>>(){});
返回响应;
}

但是当我尝试创建上述方法的泛型变体时.. 。

  public< T> ResponseWrapper此类< T> makeRequest(URI uri,Class< T> clazz){
ResponseEntity< ResponseWrapper< T>> response = template.exchange(
uri,
HttpMethod.POST,
null,
new ParameterizedTypeReference< ResponseWrapper< T>>(){});
返回响应;
}

...并且像这样调用这个方法...

  makeRequest(uri,MyClass.class)

...而不是获得 ResponseEntity< ResponseWrapper< MyClass>> 对象我得到 ResponseEntity< ResponseWrapper< LinkedHashSet> ;> 对象。

我该如何解决这个问题?它是一个RestTemplate错误?



更新1
感谢@Sotirios我理解这个概念。不幸的是,我刚刚在这里注册,所以我不能评论他的答案,所以写在这里。我不确定我是否清楚地知道如何使用 Class 键来实现建议的方法来解决 Map 问题由@Sotirios在他的回答结束时)。有人会介意给出一个例子吗?

解决方案

不,它不是一个错误。这是 ParameterizedTypeReference hack如何工作的结果。

如果你看看它的实现,它使用 Class#getGenericSuperclass() 其中声明


返回表示此类表示的实体
(类,接口,原始类型或void)的直接超类的Type。



如果超类是一个参数化类型,则返回的
对象必须准确地反映源中使用的实际类型参数 $ Type
code。


因此,如果您使用

  new ParameterizedTypeReference< ResponseWrapper< MyClass>>(){} 

它会准确地为 ResponseWrapper< MyClass> 返回类型

如果您使用

  new ParameterizedTypeReference< ResponseWrapper< T>> ;(){} 

准确地返回类型 ResponseWrapper< T> ,因为这就是它在源代码中的表现形式。



T ,它实际上是一个 TypeVariable 对象,它不知道要使用的类型,所以它使用它的默认值。

你不能使用 ParameterizedTypeReference 你提出的方式,使它在接受任何类型的意义上是通用的。考虑使用映射到预定义的 ParameterizedTypeReference 的键 Class 编写 Map >
$ b

您可以继承 ParameterizedTypeReference 并覆盖它的 getType 方法返回适当创建的 ParameterizedType 按照IonSpin


To use generic types with Spring RestTemplate we need to use ParameterizedTypeReference (Unable to get a generic ResponseEntity<T> where T is a generic class "SomeClass<SomeGenericType>")

Suppose I have some class

public class MyClass {
    int users[];

    public int[] getUsers() { return users; }
    public void setUsers(int[] users) {this.users = users;}
}

And some wrapper class

public class ResponseWrapper <T> {
    T response;

    public T getResponse () { return response; }
    public void setResponse(T response) {this.response = response;}
}

So if I'm trying to do something like this, all is OK.

public ResponseWrapper<MyClass> makeRequest(URI uri) {
    ResponseEntity<ResponseWrapper<MyClass>> response = template.exchange(
        uri,
        HttpMethod.POST,
        null,
        new ParameterizedTypeReference<ResponseWrapper<MyClass>>() {});
    return response;
}

But when I'm trying to create generic variant of the above method ...

public <T> ResponseWrapper<T> makeRequest(URI uri, Class<T> clazz) {
   ResponseEntity<ResponseWrapper<T>> response = template.exchange(
        uri,
        HttpMethod.POST,
        null,
        new ParameterizedTypeReference<ResponseWrapper<T>>() {});
    return response;
}

... and calling this method like so ...

makeRequest(uri, MyClass.class)

... instead of getting ResponseEntity<ResponseWrapper<MyClass>> object I'm getting ResponseEntity<ResponseWrapper<LinkedHashSet>> object.

How can I solve this problem? Is it a RestTemplate bug?

UPDATE 1 Thanks to @Sotirios I understand the concept. Unfortunately I'm newly registered here so I cant comment on his answer, so writing it here. Im not sure that I clearly understand how to implement the proposed approach to solve my problem with Map with Class key (Proposed by @Sotirios in the end of his answer). Would someone mind to give an example?

解决方案

No, it is not a bug. It is a result of how the ParameterizedTypeReference hack works.

If you look at its implementation, it uses Class#getGenericSuperclass() which states

Returns the Type representing the direct superclass of the entity (class, interface, primitive type or void) represented by this Class.

If the superclass is a parameterized type, the Type object returned must accurately reflect the actual type parameters used in the source code.

So, if you use

new ParameterizedTypeReference<ResponseWrapper<MyClass>>() {}

it will accurately return a Type for ResponseWrapper<MyClass>.

If you use

new ParameterizedTypeReference<ResponseWrapper<T>>() {}

it will accurately return a Type for ResponseWrapper<T> because that is how it appears in the source code.

When Spring sees T, which is actually a TypeVariable object, it doesn't know the type to use, so it uses its default.

You cannot use ParameterizedTypeReference the way you are proposing, making it generic in the sense of accepting any type. Consider writing a Map with key Class mapped to a predefined ParameterizedTypeReference for that class.

You can subclass ParameterizedTypeReference and override its getType method to return an appropriately created ParameterizedType, as suggested by IonSpin.

这篇关于在具有泛型参数的泛型方法中使用Spring RestTemplate的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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