TransWikia.com

How to avoid code redundancy with JAVA generics

Stack Overflow Asked by cosimoth on December 5, 2021

I have two similar functions which send different requests to different APIs:

// fill request
CompletableFuture<ReqType1> future = new CompletableFuture<>();
RpcClientController rpcClientController = new RpcClientController();
service1.api1(rpcClientController, request1, future::complete);
RspType1 response;
try {
    if (rpcClientController.isFailed()) {
        log.error();
        return null;
    }
    response = future.get(5, TimeUnit.SECONDS);
    if (response == null) {
        log.error();
        return null;
    }
} catch (InterruptedException e) {
    log.error("error: {}", e.getMessage());
    return null;
} catch (ExecutionException e) {
    log.error("error: {}", e.getMessage());
    return null;
} catch (TimeoutException e) {
    log.error("error: {}", e.getMessage());
    return null;
}
// process response

The other:

// fill request
CompletableFuture<ReqType2> future = new CompletableFuture<>();
RpcClientController rpcClientController = new RpcClientController();
service2.api2(rpcClientController, request2, future::complete);
RspType2 response;
try {
    if (rpcClientController.isFailed()) {
        log.error();
        return null;
    }
    response = future.get(5, TimeUnit.SECONDS);
    if (response == null) {
        log.error();
        return null;
    }
} catch (InterruptedException e) {
    log.error("error: {}", e.getMessage());
    return null;
} catch (ExecutionException e) {
    log.error("error: {}", e.getMessage());
    return null;
} catch (TimeoutException e) {
    log.error("error: {}", e.getMessage());
    return null;
}
// process response

A template method in C++ can handle this. I think C++ compiler creates two methods for <ReqType1, RspType1, SrvType1, ApiFunc1> and <ReqType2, RspType2, SrvType2, ApiFunc2>, respectively.

Nevertheless, this cannot be compiled properly in Java:

protected <Request, Service, Response> 
Response callService(Request request, Service service, Response response) {
    ...
    service.api1(rpcClientController, request, future::complete); 
    // wrong, cannot resolve method 'api1' in 'service'
}

It seems that generic type Service is the same as Object to Java compiler. So what does a generic method usually look like?

One Answer

You're pretty close with this, the way you've declared your type parameters is incorrect though. It should be more like:

protected <T extends Request, S extends Service, R extends Response> 
Response callService(T request, S service, R response) {
    ...
    service.api1(rpcClientController, request, future::complete); 
}

By convention in Java type parameters are a single uppercase letter. To get them to behave as you expect you need to bound the types; hence the extends.

Answered by psyjg47 on December 5, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP