3
\$\begingroup\$

OK, here's the problem space: Lwjgl, a graphical library, has the ability to throw an unchecked LWJGLException on certain methods - like Display.create(). This becomes a problem when you have to off-load all work done by Display onto a single thread using an ExecutorService - that's what I'm doing, unfortunately, due to how Lwjgl works. ExecutorService.submit(Runnable) does not allow you to throw unchecked exceptions. ExecutorService.submit(Callable<V>) does, however, I still have to handle that exception.

My solution? I used the strategy pattern, like so.

private final ExecutorService executor;
private final ExceptionHandler exceptionHandler;

@Inject
public LwjglWindow(@Lwjgl ExecutorService executor, @Lwjgl ExceptionHandler exceptionHandler) {
    this.executor = executor;
    this.exceptionHandler = exceptionHandler;
}

public void start() {
    executor.submit(() -> {
        try {
            Display.create();
        } catch (LWJGLException ex) {
            exceptionHandler.onException(ex);
        }
    });
}

Using dependency injection, I inject an instance of ExceptionHandler to deal specifically with exceptions originating from Lwjgl. Should an exception occur from Lwjgl, well, then, this is called (from LwjglExceptionHandler):

@Override
public void onException(Exception exception) {
    logger.trace("lwjgl encountered an error", exception);
    systemShutdownStrategy.shutdown();
}

systemShutdownStrategy is an interface that is nothing more than a strategy pattern. This is injected into the instance of LwjglExceptionHandler, so it could be a stub and do nothing or it could shut down your program (which is, as the name of the field suggests, the intent). There's always room to implement some user-friendly error notification, rather than closing quietly, but this is just here for demonstration purposes.

The reason behind my choices here is that if a LwjglException occurs, the program is pretty much guaranteed to be unrecoverable. However, I'm concerned that I might be creating a code smell by the way I implement by start() method in LwjglWindow, given the side effects possible.

So, my question is, given that this is how I am handling my LwjglExceptions, is it a code smell, and what alternatives would you suggest in that case? (Also, a general review of my conventions would be appreciated if you'd like, as obviously just getting back into Java after 2 years in the .NETsphere)

\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

Exception handling in Java has certain best practices. But not all situations are covered equally.

In this case, what you have, is a combination of logging, handling, and shutdown handling.

In this case, your handling appears to be sane. The centralization of this logging/shutdown is convenient because it essentially extracts the same functionality from multiple places in to a single place.

There are two issues that I can see:

  1. Logging in Java often is tied to the class that the log message is called from. For example, the Logger is created with a name of the class as a constructor/key.

    This means that the logging of the exception may/will be logged with the name of the ErrorHandler class rather than the class that threw the exception.

    Depending on your circumstances, this may be a problem.

  2. Logic flow in situations like this are often complicated by the return types of the class. For example, your code may look like:

    public int myMethod() {
        try {
            // .... do something ....
            return 1;
        } catch (LWJGLException ex) {
            exceptionHandler.onException(ex);
        }
    }
    

    but, that code will not compile because you need to return an int value after handling the exception.

    You know that there will never be an exit from the onException, because it shuts down. The compiler does not know that, so the compiler makes the wrong assessment of the exit path of the method.

    I recommend you change the signature of the onException class, to have a return type of RuntimeException. With that, you can have:

       } catch (LWJGLException ex) {
           throw exceptionHandler.onException(ex);
       }
    

    That will keep the compiler happy too.

\$\endgroup\$
1
  • \$\begingroup\$ I'm still working on the logging thing and am very tempted to use Guice and AOP to use the logging, rather than injecting a logger into the exception handler. I think the stack trace while not ideal will provide enough information about where the exception originated from. I like the idea of re-throwing the exception as a runtime exception, so thank you. :) \$\endgroup\$
    – Dan
    Aug 31, 2014 at 18:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.