Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google Guava EventBus and Exceptions in Event Handlers

the Guava EventBus documentation says that "handlers should not, in general, throw. If they do, the EventBus will catch and log the exception. This is rarely the right solution for error handling and should not be relied upon; it is intended solely to help find problems during development."

If you know that certain exceptions might occur you can register a SubscriberExceptionHandler with the EventBus and use it to handle these exceptions.

But what happens if an unhandled exception occurs? Normally, I would want an unhandled exception to "bubble up" the calling chain. When using a SubscriberExceptionHandler, I have access to the original exception that was thrown in the event handler, and I just want to rethrow it. But I could not figure out how.

So how can you make sure unexpected exceptions in event handlers are not "swallowed", regardless if a SubscriberExceptionHandler is used or not?

Any help would be greatly appreciated.

like image 658
Christian Guetter Avatar asked Nov 08 '15 22:11

Christian Guetter


People also ask

What is guava EventBus?

The Google Guava EventBus allows publish-subscribe-style communication between components without requiring the components to explicitly register with one another (and thus be aware of each other). The guava-eventbus: component provides integration bridge between Camel and Google Guava EventBus infrastructure.

Is EventBus synchronous?

As long as you use EventBus (rather than AsyncEventBus ), there are no synchronization issues added by the bus. The event bus simply executes you subscribers immediately in the same thread. As long as you yourself stick with a single thread, there's no multithreading and no need for any synchronization.

What is EventBus in Java?

EventBus is a publish/subscribe event bus for Android and Java. EventBus... simplifies the communication between components. decouples event senders and receivers. performs well with Activities, Fragments, and background threads.


2 Answers

Guava will not let the exception bubble up. It's forced to stop inside exceptionHandler. See source code below.

      /**
       * Handles the given exception thrown by a subscriber with the given context.
       */
      void handleSubscriberException(Throwable e, SubscriberExceptionContext context) {
        checkNotNull(e);
        checkNotNull(context);
        try {
          exceptionHandler.handleException(e, context);
        } catch (Throwable e2) {
          // if the handler threw an exception... well, just log it
          logger.log(
              Level.SEVERE,
              String.format(Locale.ROOT, "Exception %s thrown while handling exception: %s", e2, e),
              e2);
        }
      }

I post an issue on github. You can inherit EventBus and write your own exception handle logic.

package com.google.common.eventbus;

import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.SubscriberExceptionContext;

/**
 * A eventbus wihch will throw exceptions during event handle process.
 * We think this behaviour is better.
 * @author ytm
 *
 */
public class BetterEventBus extends EventBus {

    public BetterEventBus() {}

    /**
     * Creates a new EventBus with the given {@code identifier}.
     *
     * @param identifier a brief name for this bus, for logging purposes. Should be a valid Java
     *     identifier.
     */
    public BetterEventBus(String identifier) {
        super(identifier);
    }

    /**
     * Just throw a EventHandleException if there's any exception.
     * @param e
     * @param context
     * @throws EventHandleException 
     */
    @Override
    protected void handleSubscriberException(Throwable e, SubscriberExceptionContext context) throws EventHandleException {
        throw new EventHandleException(e);
    }
}
like image 177
TimYi Avatar answered Sep 19 '22 15:09

TimYi


If you want to deal with unchecked exceptions, you could implement SubscriberExceptionHandler's method like this:

public void handleException(Throwable exception, SubscriberExceptionContext context) {
    // Check if the exception is of some type you wish to be rethrown, and rethrow it.
    // Here I'll assume you'd like to rethrow RuntimeExceptions instead of 'consuming' them.
    if (exception instanceof RuntimeException) {
        throw (RuntimeException) exception;
    }

    // If the exception is OK to be handled here, do some stuff with it, e.g. log it.
    ...
}

After creating a class implementing the SubscriberExceptionHandler interface, you can pass its instance to the EventBus's constructor:

EventBus eventBus = new EventBus(new MySubscriberExceptionHandler());

And done, eventBus will use your exception handler which will let RuntimeExceptions bubble up.

like image 24
Tosz Avatar answered Sep 18 '22 15:09

Tosz