5

This is a plain Java 8+ question, no frameworks used.

We are producing an API for a higher layer which deals with the presentation layer among other activities. We have and interface agreed with the invoker, so they are happy to receive some particular exceptions we throw.

At the same time, we are also using other APIs under the same agreement, so we can do stuff by ourselves and throw exceptions or we can invoke other APIs which throw the agreed exceptions. Currently, we do nothing with the exceptions thrown by the APIs we are invoking.

Thing is, we are the best positioned in this infrastructure to deal with intermediate activities while exceptions are thrown, so we need to capture both, our exceptions and the exceptions provided by those we are invoking; basically reporting the issue, raising system controls, etc, and then re-throw the original exception so the top layer keeps as it is now.

We have around 300 methods in the entry point class of our API:

public void method1 (arguments for method 1) {
...
}

...

public void method300 (arguments for method 300) {
...
}

I clearly understand that I can create a method to centralise the actions to be taken in the exception management, something like:

public void myExceptionHandler (Exception e) {
    if (e instanceOf X) {
    } else if ...
    ...
    throw particularExceptionAccordingTheCase 
}

But I'd also avoid modifying those 300 methods.

Any idea how to inject a try-catch in those 300 methods to send the Exception to myExceptionHandler without really adding a try-catch in each of them?

Any comments and ideas are much appreciated!

----------- After mprev0 suggestion -------------------------------

I tried this approach. It really catches the exception and so on, but I can't re-trow an Exception: I'm forced to catch it, but this goes against the requirement of re-sending the exception back to the top layer. While I can throw an Error, I got a compiler error at line throw new FileNotFoundException();

public class myExceptionHandler implements Thread.UncaughtExceptionHandler {

    @Override
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("gotcha!");
        if (e instanceof java.lang.Error) {
            System.out.println("AAT-CORE: Fatal Error");
            throw new java.lang.Error(e.getCause());

        } else if (e instanceof java.lang.Exception) {
            System.out.println("AAT-CORE: Exception Error");
            throw new FileNotFoundException();
        }
    }

}

Any ideas?

------------ After some more digging, fixed with a decorator pattern -------

Previous class implementation does not work, as I can't change the signature of the method and I need to re-throw the java.lang.Exception.

Using a decorator and handling the interface there makes the trick. As a summary:

Top layer class:

public class TopLayer {
    public static void main (String[] args) {
        MiddleLayer m = new MiddleLayer();
        m.method1();
    }
}

Bottom layer class contains specific APIs and some implementation, the only interesting thing is that it contains java.lang.Exceptions uncontrolled, expecting the top layer to do this job. But, we are working in the middle and we will do this job:

public class MiddleLayer extends BottomLayer {

    public MiddleLayer () {
        final UncaughtExceptionHandler subclass = Thread.currentThread().getUncaughtExceptionHandler();
        Thread.currentThread().setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread thread, Throwable ex) {

                System.out.println("gotcha2!");
                // carry on with prior flow
                subclass.uncaughtException(thread, ex);
            }
        });

    }

}

In this way, I can get the system.out and the java.lang.Exception is propagated to the Top Layer.

Decorator inspiration came from here: Rethrow UncaughtExceptionHandler Exception after Logging It

Additional comments are welcome!

Marko Previsic
  • 1,820
  • 16
  • 30
JBC
  • 51
  • 6
  • 2
    *We have around 300 methods in the entry point class of our API*, **twitches**. Please have a look at [Separation of concerns](https://en.wikipedia.org/wiki/Separation_of_concerns) – Lino May 08 '19 at 11:44
  • @JBC Good job finding out how to adapt it to work also for checked exceptions, thanks for sharing it! I updated my answer to include also your findings. Btw. if my or any other answer has solved your question please consider [accepting it](https://meta.stackexchange.com/q/5234/179419) by clicking the check-mark. This indicates to the wider community that you've found a solution and gives some reputation to both the answerer and yourself. Of course, there is no obligation to do this, but it would be nice :-) – Marko Previsic May 10 '19 at 07:21

3 Answers3

4

You can solve this by implementing the java.lang.Thread.UncaughtExceptionHandler interface:

public class MyExceptionHandler implements Thread.UncaughtExceptionHandler {

    @Overrides
    public void uncaughtException(Thread t, Throwable e) {
            if (e instanceOf X) {
            } else if ...
            ...
            throw particularExceptionAccordingTheCase 
    }
}

Then you associate it to all threads as follows:

Thread.setDefaultUncaughtExceptionHandler(new MyExceptionHandler())

This will configure the exception handler to handle all uncaught exceptions in all threads of your application.

Note that this will only work for exceptions that aren't yet explicitly handled somewhere in your code and if there is no other handler configured for some particular thread (the uncaught exception handler can also be set for some specific thread).

EDIT: As discovered by @JBC, the above approach will not work for checked exceptions since we are forced to catch them explicitly in our uncaughtException method (note that we cannot add a throws clause to an overridden method). While it will work without problems if we only want to re-throw subtypes of RuntimeException and Error, there is a little adaptation needed if we want to make it work - you can find it explained in @JBC's question.

Marko Previsic
  • 1,820
  • 16
  • 30
  • 2
    Thanks mprev0, that sounds like a good approach. Let me spend some hours with this and revert back shortly. – JBC May 09 '19 at 12:35
  • 2
    That needs a decorator pattern! – JBC May 09 '19 at 17:22
  • 1
    Hi JBC, thanks for your feedback! Sorry, I somehow missed the detail that catched exceptions will also be re-thrown by your global exception handler, I thought that probably you will throw only runtime exceptions since checked exceptions are forcing us to catch them. Luckily you found a solution to this problem, thanks for sharing it, looks nice! – Marko Previsic May 09 '19 at 18:24
0

As you can see in the question updates, the final solution is a combination of two different approaches, in one side, having the mprev0 approach of implementing the java.lang.Thread.UncaughtExceptionHandler and, on top of this, adding a Decoration pattern to be able to re-throw a run-time exception.

There were no additional approaches so far, so I'm closing the question and bring this as the most complete response.

More information about UncaughtExceptionHandler can be found in the Java documentation, but as always, is short on examples, and here: Advanced exception handling Thread.UncaughtExceptionHandler Example

More information on Decorator pattern usage, can be found here: Decorator Design Pattern in Java Design Patterns - Decorator Pattern

And how to use to manipulate exceptions here: Rethrow UncaughtExceptionHandler Exception after Logging It

JBC
  • 51
  • 6
-1

You could also create a proxy API on top of your current API, have an invocation handler method in the proxy and put this method in a try catch block.

https://docs.oracle.com/javase/8/docs/technotes/guides/reflection/proxy.html

https://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Proxy.html

Sameer
  • 757
  • 1
  • 14
  • 35
  • Hi Sameer, thanks for your answer. I'm not familiar with proxy APIs. I'll need to spend some time with the documentation and make some testings, as this looks like an alternative not only for capturing exceptions but also for adding additional functionality. Any examples will be appreciated, but not required, as I'm sure will find some around. Thanks! – JBC May 09 '19 at 13:26
  • Hi Sameer, I've been making some tests, and sorry but I can't find a proper model. I've been checking basically the links you provided plus https://dzone.com/articles/java-dynamic-proxy and https://www.baeldung.com/java-dynamic-proxies. The only way of implementation I see is to create a mimic class A(method1, ..., method300) which invokes the proxy and this proxy to the real class, so in the proxy I can implement the special behavior... but is there a way to avoid the mimic class with the 300 methods? Thanks again. – JBC May 09 '19 at 15:05