Home > Net >  Cannot use base class without passing its type in Java
Cannot use base class without passing its type in Java

Time:12-27

I want to create a common service and common request as shown below:

public interface CommonService {

    CommandDTO createOrUpdate(CommonRequest request);
}

Then implement this service as shown below:

public class CompanyARequest extends CommonRequest {

    // properties
}
public class CompanyAServiceImpl implements CommonService {

    @Override
    public CommandDTO createOrUpdate(CompanyARequest request) {
        // ...
    }
}

However, although CompanyARequest is inherited from CommonRequest, createOrUpdate method throws "Method does not override method from its superclass" error.

On the other hand, if I use generic for the request, the error is gone, but if I use generic for request and dto, there will be too much letter is used and I just want to use generic letters for entities that will be used in CommonService. SO, how can I fix this problem? Is there any mistake of my implementation?

CodePudding user response:

The CompanyAServiceImpl::createOrUpdate implementation only contemplates a small subset of the entire space defined by CommonService::createOrUpdate. That is why it is stated that "method does not override method from its superclass" (not entirely, at least).

To see it, think of a certain method that receives as parameter any CommonService, for example:

void runService(CommonService commonService) { ... }

How can runService know (at compile time) what is the correct parameter for commonService.createOrUpdate? It only knows that it must be CommonRequest (or, transitively, any class that extends it). But your CompanyAServiceImpl::createOrUpdate implementation only supports one of them.

In other words, createOrUpdate must support any parameter that is a CommonRequest.

The best you can do depends on the type of abstraction you are looking for (and your question does not describe the problem to be solved).

However, you might be looking for something similar to:

interface CommonRequest {
    String requestDescription();
}
interface CommonService<Request extends CommonRequest> {
    String serviceName();
    boolean createOrUpdate(Request request);
}

static class CompanyARequest implements CommonRequest {
    public String requestDescription() { return "A Req"; }
}
static class CompanyAService implements CommonService<CompanyARequest> {
    public String serviceName() { return "A Co"; }
    public boolean createOrUpdate(CompanyARequest companyARequest) { return true; }
}

static class CompanyBRequest implements CommonRequest {
    public String requestDescription() { return "B Req"; }
}
static class CompanyBService implements CommonService<CompanyBRequest> {
    public String serviceName() { return "B Co"; }
    public boolean createOrUpdate(CompanyBRequest companyBRequest) { return false; }
}

Now, all processes calling createOrUpdate will be forced to know which parameter is the correct one, but common processes for all companies can still share a single implementation, for example running with logging:

static <R extends CommonRequest> void runService(CommonService<R> service, R request) {
    System.out.printf("Running service '%s':%n", service.serviceName());
    if(service.createOrUpdate(request))
        System.out.printf(" - Success with parameter '%s'.%n", request.requestDescription());
    else
        System.out.printf(" ! Error with parameter '%s'.%n", request.requestDescription());
}

if we run

runService(new CompanyAService(), new CompanyARequest());
runService(new CompanyBService(), new CompanyBRequest());

we get

Running service 'A Co':
 - Success with parameter 'A Req'.
Running service 'B Co':
 ! Error with parameter 'B Req'.

Of course, all this is if that parameter (CommonRequest) and that method (createOrUpdate) are going to be used generically in many places in your application, otherwise, just add a new method to your company:

public class CompanyAServiceImpl implements CommonService {

    @Override
    public CommandDTO createOrUpdate(CompanyRequest request) {
        // ...
    }

    public CommandDTO createOrUpdateWithA(CompanyARequest request) {
        // ...
    }
}

CodePudding user response:

You are looking for a generic interface from what I understand:

public interface CommonService<C extends CommonRequest> {

    CommandDTO createOrUpdate(C request);
}

public class CompanyAServiceImpl implements CommonService<CompanyARequest> {

    @Override
    public CommandDTO createOrUpdate(CompanyARequest request) {
        // ...
    }
}

If you were to define it like you first did, the issue is that any CommonRequest should be accepted by the method according to its definition in the interface.

  • Related