PUBLIC OBJECT

Future Guice: Providers that throw unchecked exceptions

As previously mentioned, I'm cataloging Guice's changes since 1.0.

Suppose you have a provider that throws an unchecked exception:

class PhaseOfTheMoonProvider implements Provider<PhaseOfTheMoon> {
  @Inject Observatory observatory;

  public PhaseOfTheMoon get() {
    if (observatory.isNighttime()) {
      return observatory.getCurrentPhase();
    }

    throw new IllegalStateException("Can't see the moon unless it's nighttime.");
  }
}`</pre>
For the most part, unchecked exceptions are useful for validating pre- and postconditions. But a problem arises when code attempts to catch the specific exception thrown by a provider. Suppose this is our calling code:
<pre class="prettyprint">`  @Inject Provider&lt;PhaseOfTheMoon&gt; phaseOfTheMoonProvider;

  public boolean isFullMoon() {
    try {
      PhaseOfTheMoon phaseOfTheMoon = phaseOfTheMoonProvider.get();
      return phaseOfTheMoon == PhaseOfTheMoon.FULL;
    } catch (IllegalStateException e) {
      return false;
    }
  }`</pre>
This code works, but it's prone to regress as the provider code is maintained. For example, if the provider code is changed to throw `NoMoonlightException`, our application breaks without any notice from the compiler. And should other unchecked exceptions be thrown, the only way to reliably handle them is to suffix all provider access with an ugly `catch (RuntimeException e)` block.

### Enter ProvisionException

To simplify this situation, recent snapshots of Guice make `ProvisionException` public, and guarantee that that will be the only exception type thrown by injected providers. Client code only needs to catch `ProvisionException` in order to recover from a failed provider. 

To implement this, Guice wraps user-supplied providers and performs exception-chaining to rethrow arbitrary exceptions as `ProvisionException`. It embeds contextual information in the provision exception, which simplifies diagnosing problems with indirectly-injected values.

The new client code can catch `ProvisionException` instead. This code will continue to work, even if the `Provider&lt;PhaseOfTheMoonProvider&gt;` changes its thrown types:
<pre class="prettyprint">`  public boolean isFullMoon() {
    try {
      PhaseOfTheMoon phaseOfTheMoon = phaseOfTheMoonProvider.get();
      return phaseOfTheMoon == PhaseOfTheMoon.FULL;
    } catch (ProvisionException e) {
      return false;
    }
  }

This is the Guice change that I'm most anxious about. It's makes a nontrivial change in Guice's behaviour in an area that is least likely to have test coverage - the exceptional case. How good are your unit tests?

PS - for checked exceptions, look at the throwing providers extension.