mercredi 5 janvier 2022

reflection: getting the proper prameterized return type (List) from a generic method

Good Day!

I am experimenting a little bit with reflections and I've come to the following problem:

In short, details below:

I have a method from an interface that also only inherits this method from another interface and the return type is List<RS> (RS extends AbstractResponseObject). How do I get the methods return type for example List instead of List<RS> in a way similar to

ParameterizedType genericReturnType = (ParameterizedType) method.getGenericReturnType();

I have a main interface describing a rest interface running on my backend, similar to this:

public interface EntityRestController<RS extends AbstractResponseObject> {
    @RequestMapping(value = "/", method = RequestMethod.GET)
    List<RS> findAll();

    ...
}

And for each entity, I have an interface just like this:

@RequestMapping("rest/customer")
public interface ICustomerRestController extends EntityRestController<ResponseCustomer> {

}

the latter one is empty and should only have methods for queries specific to the entity. but in any case it declares the endpoint for its entity.

now for all my entity interfaces I create a proxy using

E proxyInstance = (E) Proxy.newProxyInstance(
                    restInterface.getClassLoader(),
                    new Class[]{restInterface},
                    (proxy, method, args) -> handleInvoke(restInterface, method, args));

once a method is called handleInvoke is called and I check for @RequestMapping and its value for the path as well as its method and use these information creating the rest call using WebClient.

now I wonder how do I get the proper return type of my findAll() method returning a List? I have created the following code as an example:

        Class<?> returnType = method.getReturnType();
        ParameterizedType genericReturnType = (ParameterizedType) method.getGenericReturnType();
        WebClient.ResponseSpec responseSpec = webClient.get().uri(path).retrieve();
        Mono<?> mono = responseSpec.bodyToMono(ParameterizedTypeReference.forType(genericReturnType));
        Object o = mono.block(Duration.ofSeconds(30));
        return o;

using only returnType in responseSpec.bodyToMono would give me a List containing a HashMap with all the Customer information. Obviously I expect a List<ResponseCustomer> as a result. Using genericReturnType in responseSpec.bodyToMono, as shown in my example, throws an exception:

InvalidDefinitionException: Cannot construct instance of x.x.x.AbstractResponseObject (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information

which makes sense because the actual method is in the rather generic EntityRestController interface and returns RS which extends AbstractResponseObject. But how would I get the actual ResponseCustomer type?

any help is very appreciated.

cheers!





Aucun commentaire:

Enregistrer un commentaire