简体   繁体   English

如何通过Class类型的 <T> 在通用方法中

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM