[英]How to pass Class type of <T> in a generic method
I am trying to write a generic method so I can reuse it for multiple Request and response types. 我正在尝试编写一种通用方法,以便可以将其重用于多种请求和响应类型。 This is the non-generic method 这是非通用方法
public ReservationBookingResponse invokeService(String endPoint, ReservationBookingRequest reservationBookingRequest, HttpServletRequest httpServletRequest) throws APIException {
ResponseEntity<ReservationBookingResponse> response = null;
try {
String authToken = getAuthToken(restTemplate, httpServletRequest);
HttpEntity<ReservationBookingRequest> entity = new HttpEntity<ReservationBookingRequest>(reservationBookingRequest, addAuthorizationHeader(authToken));
response = restTemplate.postForEntity(endPoint, entity, ReservationBookingResponse.class);
} catch (Exception e) {
throw new APIException(e);
}
return response.getBody();
}
This is the generic method I wrote 这是我写的通用方法
public default T invoke(String endPoint, K requestBean, HttpServletRequest httpServletRequest) throws APIException {
RestTemplate restTemplate=new RestTemplate();
ResponseEntity<T> response = null;
try {
String authToken = getAuthToken(restTemplate, httpServletRequest);
HttpEntity<K> entity = new HttpEntity<K>(requestBean, addAuthorizationHeader(authToken));
response = restTemplate.postForEntity(endPoint, entity, T);
} catch (Exception e) {
throw new APIException(e);
}
return response.getBody();
}
Now the problem is in response = restTemplate.postForEntity(endPoint, entity, T);
现在问题出在response = restTemplate.postForEntity(endPoint, entity, T);
I am getting an exception "T cannot be resolved to a type" in the non generic(former) method response = restTemplate.postForEntity(endPoint, entity, ReservationBookingResponse.class);
我在非通用(以前的)方法中收到“无法将T解析为类型”的异常response = restTemplate.postForEntity(endPoint, entity, ReservationBookingResponse.class);
this works fine. 这很好。
Now I can not do T.class as it is not allowed. 现在,我不能执行T.class,因为这是不允许的。 Can someone please tell me how to pass Class<T>
to the method. 有人可以告诉我如何将Class<T>
传递给方法。
This is what the postforEntity method expects 这就是postforEntity方法所期望的
@Override
public <T> ResponseEntity<T> postForEntity(String url, Object request, Class<T> responseType, Object... uriVariables)
throws RestClientException {
You need to be given the Class<T>
at some point by the caller. 调用者有时需要为您提供Class<T>
。
The most straightforward way is to require the caller to provide the class when calling invoke
. 最直接的方法是要求调用者在调用invoke
时提供类。 It is what Piotr Wilkin suggests and what you did in your answer. 这就是皮奥特·威尔金(Piotr Wilkin)的建议以及您所做的回答。 It however creates more boilerplate than needed, and there is a better option. 但是,它会创建比所需更多的样板,并且有更好的选择。
Since T
is a generic of the whole object, you could provide the Class<T>
to the constructor, like: 由于T
是整个对象的泛型,因此可以向构造函数提供Class<T>
,例如:
private final Class<T> type; // some prefer naming like clazz
public MyClassThatHasTheInvokeMethod(Class<T> type) { /* set the field(s) here */ }
Then, you can easily provide the type
to any method call that needs Class<T>
. 然后,您可以轻松地将type
提供给需要Class<T>
任何方法调用。
You can't. 你不能
Because of type erasure, the type T
is basically not provided at runtime in any way. 由于类型擦除,基本上在运行时不以任何方式提供类型T
The only case in which you can ever retrieve a type T
is in case of a non-generic class that inherits from a specific case of a generic class (ie Foo extends Bar<Something>
), in this case you can retrieve the Something
. 唯一可以检索到类型T
的情况是,一个非泛型类继承自一个泛型类的特定情况(即Foo extends Bar<Something>
),在这种情况下,您可以检索Something
。
In all other cases, unfortunately, you have to use boilerplate - pass the class object explicitly. 不幸的是,在所有其他情况下,您必须使用样板文件-显式传递类对象。 If any of your constructor arguments is an object of type T
, you can use .getClass()
instead to avoid the boilerplate, otherwise you have to pass the class manually. 如果任何构造函数参数是T
类型的对象,则可以使用.getClass()
来避免样板,否则必须手动传递该类。
This is what I had to do to make to make it work, pass the class type as an argument from calling method. 这是我要做的,才能使其正常工作,将类类型作为调用方法的参数传递。
Quick fix Solution -1 快速解决方案-1
public T postRequestToService(String endPoint, K requestBean, HttpServletRequest httpServletRequest,
Class<T> classType) throws APIException {
response = restTemplate.postForEntity(endPoint, entity, classType);
and in the calling method 并在调用方法中
postRequestToService(endPoint+addOnAvailability, addOnAvailabilityRequest,
httpServletRequest, AddOnAvailabilityResponse.class);
However a better solution is below one - Solution -2 但是,一个更好的解决方案是低于-解决方案-2
Define a constructor, even though this happens to be an abstract class 定义一个构造函数,即使这恰好是一个抽象类
public class PegasusService<K, T> {
private Class<K> requestClass;
private Class<T> responseClass;
public PegasusService(Class<K> requestClass, Class<T> responseClass) {
this.requestClass = requestClass;
this.responseClass = responseClass;
}
and in the child class pass the class types in the constructor. 并在子类中传递构造函数中的类类型。
AddOnAvailabilityService() {
super(AddOnAvailabilityRequest.class, AddOnAvailabilityResponse.class);
}
So this code works fine response = restTemplate.postForEntity(endPoint, entity, responseClass);
因此,此代码可以正常工作response = restTemplate.postForEntity(endPoint, entity, responseClass);
No need to pass the class type. 无需传递类类型。
This way we dont have to add an extra argument or change the method definition. 这样,我们不必添加额外的参数或更改方法定义。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.