Agreed API

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
@Documented
public @interface BeforeHandles
{
    /**
     * Precedence relative to callbacks for the same type
     */
    int ordinal() default 0;
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
@Documented
public @interface Handles
{
    /**
     * Precedence relative to handlers for the same type
     */
    int ordinal() default 0; //TODO discuss Precedence
}
/**
 * Marker for types containing Exception Handler methods.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface ExceptionHandler
{
}
/**
 * Payload for an exception to be handled.  Implementations of this interface should not expose internals and remain
 * immutable for this contract.
 *
 * @param <T> Exception type this event represents
 */
public interface ExceptionEvent<T extends Throwable>
{
    /**
     * The exception causing this event.
     */
    T getException();

    /**
     * Instructs the dispatcher to abort further processing of handlers.
     */
    void abort();

    /**
     * Instructs the dispatcher to throw the original exception after handler processing.
     */
    void throwOriginal();

    /**
     * Instructs the dispatcher to terminate additional handler processing and mark the event as handled.
     */
    void handled();

    /**
     * Default instruction to dispatcher, continues handler processing.
     */
    void handledAndContinue();

    /**
     * Similar to {@link ExceptionEvent#handledAndContinue()},
     * but instructs the dispatcher to markHandled to the next element
     * in the cause chain without processing additional handlers for this cause chain element.
     */
    void skipCause();

    /**
     * Instructs the dispatcher to allow this handler to be invoked again.
     */
    void unmute();

    /**
     * Rethrow the exception, but use the given exception instead of the original.
     *
     * @param t Exception to be thrown in place of the original.
     */
    void rethrow(Throwable t);

    /**
     * Check to see if this exception has been handled.
     */
    boolean isMarkedHandled();
}
//TODO discuss the introduction of an interface
/**
 * Information about the current exception and exception cause container.  This object is not immutable.
 */
@Typed()
public class ExceptionStackEvent implements Serializable
{
    private static final long serialVersionUID = -6069790756478700680L;

    /**
     * Builds the stack from the given exception.
     *
     * @param exception Caught exception
     */
    public ExceptionStackEvent(final Throwable exception)
    {
        //...
    }

    public Collection<Throwable> getCauseElements()
    {
        //...
    }

    /**
     * Test if iteration is finished
     *
     * @return finished with iteration
     */
    public boolean isLast()
    {
        //...
    }

    public Throwable getNext()
    {
        //...
    }

    public Collection<Throwable> getRemaining()
    {
        //...
    }

    /**
     * Tests if the current exception is the root exception
     *
     * @return Returns true if iteration is at the root exception (top of the inverted stack)
     */
    public boolean isRoot()
    {
        //...
    }

    /**
     * Current exception in the iteration
     *
     * @return current exception
     */
    public Throwable getCurrent()
    {
        //...
    }

    /**
     * Internal only.
     *
     * @param elements new stack.
     */
    public void setCauseElements(Collection<Throwable> elements)
    {
        //...
    }
}
/**
 * Entry point event into the Catch system.  This object is nearly immutable, the only mutable portion
 * is the handled flag.
 */
@Typed()
public class ExceptionToCatchEvent implements Serializable
{
    /**
     * Constructor that adds qualifiers for the handler(s) to run.
     * Typically only integrators will be using this constructor.
     *
     * @param exception  Exception to handle
     * @param qualifiers qualifiers to use to narrow the handlers called
     */
    public ExceptionToCatchEvent(Throwable exception, Annotation... qualifiers)
    {
        //...
    }

    /**
     * Basic constructor without any qualifiers defined.
     *
     * @param exception Exception to handle.
     */
    public ExceptionToCatchEvent(Throwable exception)
    {
        //...
    }

    public Throwable getException()
    {
        //...
    }

    /**
     * Internal only.
     *
     * @param handled new value
     */
    public void setHandled(boolean handled)
    {
        //...
    }

    /**
     * Test to see if the exception has been handled via Solder Catch.
     *
     * @return test if the exception has been through Solder Catch handling.
     */
    public boolean isHandled()
    {
        //...
    }

    /**
     * Qualifiers with which the instance was created.
     *
     * @return Qualifiers with which the instance was created.
     */
    public Set<Annotation> getQualifiers()
    {
        //...
    }
}
/**
 * Flow control enum.  Used in the dispatcher to determine how to markHandled.
 */
public enum ExceptionHandlingFlow
{
    HANDLED,
    HANDLED_AND_CONTINUE,
    SKIP_CAUSE,
    ABORT,
    THROW_ORIGINAL,
    THROW
}
/**
 * Container for the exception and it's stack trace.
 */
@Typed()
public final class ExceptionStackItem implements Serializable
{
    public ExceptionStackItem(final Throwable cause)
    {
        //...
    }

    public ExceptionStackItem(Throwable throwable, StackTraceElement[] stackTraceElements)
    {
        //...
    }

    public StackTraceElement[] getStackTraceElements()
    {
        //...
    }

    public Throwable getThrowable()
    {
        //...
    }
}
/**
 * Meta data interface about an exception handler. It is the responsibility of the
 * implementation to support {@link javax.enterprise.inject.spi.InjectionPoint}s and to
 * validate those {@link javax.enterprise.inject.spi.InjectionPoint}s.
 *
 * @param <T> Exception for which this handler is responsible
 */
public interface HandlerMethod<T extends Throwable>
{
    /**
     * Obtains the set of handled event qualifiers.
     */
    Set<Annotation> getQualifiers();

    /**
     * Obtains the handled event type.
     */
    Type getExceptionType();

    /**
     * Flag indicating this handler should be invoked during the before traversal.
     */
    boolean isBeforeHandler();

    /**
     * Calls the handler method, passing the given event object.
     *
     * @param event event to pass to the handler.
     */
    void notify(ExceptionEvent<T> event);

    /**
     * Obtains the precedence of the handler.
     */
    int getOrdinal();

    /**
     * Basic {@link Object#equals(Object)} but must use all of the get methods from this interface to
     * maintain compatibility.
     *
     * @param o Object being compared to this.
     * @return true or false based on standard equality.
     */
    @Override
    boolean equals(Object o);

    @Override
    int hashCode();
}

Under discussion

  • Exception Handlers
  • Entry into the Exception Handling system

API/SPI

Use-cases

Fire and observe exceptions

An exception happens either in some business logic or from the container (maybe a session timed out or something like that). Developers need a simple, easy to use way to handle exceptions in a uniform way. They also need to be able to tell, after exception handling, if the exception was actually handled (a handler was found for the particular exception type or super type) or if it needs to be bubbled up to a higher level.

Scenario

Business method using try / catch
public void myBusinessMethod(...) {
    try {
        ...
    } catch (Exception e) {
        // entry into exception handling system
}
JSF integration
public void handle() throws FacesException {
    // iterate over exceptions
    // entry into exception handling system
    // exception handling inspection
}
JAX-RS integration
public class MyExceptionMapper implements ExceptionMapper<Throwable> {
    public Response toResponse(E exception) {
        // entry into exception handling system
        // exception handling inspection
    }
}
  • No labels