1

I have an interface:

public interface ThirdPartySystemCaller {
    void sendRequest(String request) throws ThirdPartySystemException;
}

And implementation:

@Slf4j
@Service
public class ThirdPartySystemCallerImpl implements ThirdPartySystemCaller {

    @Override
    public void sendRequest(String request) throws ThirdPartySystemException {

        if (request == null) throw new ThirdPartySystemException();

        log.info("send: {}", request);
    }
}

And I have a CryptoService witch can sign request:

public interface CryptoService {
    String signRequest(String request) throws CryptoException;
}

And It implementation:

@Slf4j
@Service
public class CryptoServiceImpl implements CryptoService {

    @Override
    public String signRequest(String request) throws CryptoException {
        if (request.length() > 100) throw new CryptoException(); //just for example
        return "signed " + request;
    }
}

Now, I can use these services:

String signedRequest = cryptoService.signRequest("Hello"); 
thirdPartySystemCaller.sendRequest(signedRequest); 

But I need to call both services each time. I want to create Proxy:

@Slf4j
@Service
public class ThirdPartySystemCallerSignedProxy implements ThirdPartySystemCaller {

    private final ThirdPartySystemCaller thirdPartySystemCaller;
    private final CryptoService cryptoService;

    public ThirdPartySystemCallerSignedProxy(ThirdPartySystemCaller thirdPartySystemCaller, CryptoService cryptoService) {
        this.thirdPartySystemCaller = thirdPartySystemCaller;
        this.cryptoService = cryptoService;
    }

    @Override
    public void sendRequest(String request) throws ThirdPartySystemException {
        String signedRequest = cryptoService.signRequest(request);
        thirdPartySystemCaller.sendRequest(signedRequest);
    }
}

But my ThirdPartySystemCallerSignedProxy implement ThirdPartySystemCaller interface and sendRequest method throw only ThirdPartySystemException. But if cryptoService throw CryptoException I need throw it too.

How can I do it?

I was thinking to make unchecked exceptions, But I need to be checked.

ip696
  • 6,574
  • 12
  • 65
  • 128
  • This is one of the many reasons I try to avoid exceptions where I can, they can make code overly complicated and fragile. Can you add exceptions to the proxy signature? Is there any way you can catch the exception in your proxy method and deal with it sensibly there? – chips Mar 29 '19 at 13:58

1 Answers1

0

Create base exception

You can create abstract exception BusinessException which can be a base exception for ThirdPartySystemException and CryptoException. Now, you can define that sendRequest method throws BusinessException and real exception depends from given problem.

Facade

ThirdPartySystemCallerSignedProxy is a bad name because it reminds Proxy pattern which is not what you have implemented. This class reminds Facade pattern because you want to create unified interface with simpler API for two different interfaces. In that case you can wrap CryptoException if it will be thrown into ThirdPartySystemException or also create base exception and declare it in method. It is even better because you do not know which kind of exception will be thrown but for sure it will be BusinessException.

Chain of Responsibility

Many libraries use Chain of Responsibility to handle request -> response communication. All chain cells need to implement the same interface with base exception in declaration if needed. You can build the chain in bean definition. It is a little bit easier to maintain because all cells are independent and does not have to know about each other as in Facade. You can build chain in @Bean method declaration like below:

@Bean
public ServiceChainCell thirdPartyCaller() {
    CryptoService crypto = cryptoService();
    ThirdPartySystemCaller caller = thirdPartySystemCaller();

    // Create chain
    crypto.setNext(caller);

    return crypto;
}

setNext method comes from ServiceChainCell interface which also should have sendRequest(String request) method.

Read more about these patterns and you will find the best solution for you.

Michał Ziober
  • 37,175
  • 18
  • 99
  • 146
  • Thank you! I think `BaseException` is bad practice for this case. Because now `ThirdPartySystemCaller ` and `CryptoService ` don't know anything about each other and I want to stay like this. In the second part, I don't agree. I don't want to create Facade. I create the Proxy pattern. I have original `callerService` with some interface. And create `ProxyService` with the same interface. But I add end-to-end functionality - `sign request`. It looks like Decorator maybe. I don't implement different interfaces in my Proxy/Decorator class like in Facade. But I will try a `ChainResponsibility`. – ip696 Mar 31 '19 at 10:01