Locked History Actions

guice/Manual/Extensions/ThrowingProviders

ThrowingProvider

Guiceは(プロバイダによる)インスタンス生成中の例外をうまくハンドリングできない。

  • プロバイダ実装はRuntimeExceptionのみを投げることが可能である(訳注:チェック例外は利用できない)。

  • プロバイダの呼び出し側は、それが投げる例外をキャッチすることができない。なぜなら、それらはProvisionExceptionによってラップされているからである。

  • プロバイダを利用せず、インスタンスに直接注入しようとすると、そのインスタンスの生成に失敗する可能性がある。
  • Exceptions cannot be advertised in the API.

ThrowingProvidersはプロバイダの代替であり、チェック例外を投げることができる。

  • API consistent with Provider.
  • Scopable
  • Standard binding DSL

ThrowingProviderインターフェースはProviderと同様であるが、一般例外タイプを持つ。

public interface ThrowingProvider<T,E extends Exception> {
  T get() throws E;
}

それぞれのアプリケーション例外について、ThrowingProviderを拡張するインターフェースを作成するとよい。 我々のニュースウィジェットアプリケーションではFeedUnavailableExceptionを投げるFeedProviderを作成した。

public interface FeedProvider<T> extends ThrowingProvider<T, FeedUnavailableException> { }

WordlNewsFeedProviderSportsFeedProviderの実装を作成し、それらをモジュール内にてThrowingProviderBinderを使ってバインドする。

public static class FeedModule extends AbstractModule {
  protected void configure() {
    ThrowingProviderBinder.create(binder())
        .bind(FeedProvider.class, BbcFeed.class)
        .annotatedWith(WorldNews.class)
        .to(WorldNewsFeedProvider.class)
        .in(HourlyScoped.class);

    ThrowingProviderBinder.create(binder())
        .bind(FeedProvider.class, BbcFeed.class)
        .annotatedWith(Sports.class)
        .to(SportsFeedProvider.class)
        .in(QuarterHourlyScoped.class);
  }
}

最後にFeedProviderをアプリケーション全体に渡って注入する。 そのget()呼び出しではいつでもFeedUnavailableExceptionをハンドリングすべきことをコンパイラが教えてくれる。

public class BbcNewsWidget {
  private final FeedProvider<BbcFeed> worldNewsFeedProvider;
  private final FeedProvider<BbcFeed> sportsFeedProvider;

  @Inject
  public BbcNewsWidget(
      @WorldNews FeedProvider<BbcFeed> worldNewsFeedProvider,
      @Sports FeedProvider<BbcFeed> sportsFeedProvider) {
    this.worldNewsFeedProvider = worldNewsFeedProvider;
    this.sportsFeedProvider = sportsFeedProvider;
  }

  public GxpClosure render() {
    try {
      BbcFeed bbcWorldNews = worldNewsFeedProvider.get();
      BbcFeed bbcSports = sportsFeedProvider.get();
      return NewsWidgetBody.getGxpClosure(bbcWorldNews, bbcSports);
    } catch (FeedUnavailableException e) {
      return UnavailableWidgetBody.getGxpClosure();
    }
  }
}

スコーピングに関するノート

スコープもプロバイダに関して同じように動作する。 get()が呼び出されるときには、返されたオブジェクトは適切にスコープされる。 例外も同じくスコープされる。 例えば、worldNewsFeedProvider.get()が例外を投げると、その同じ例外がスコープ内のすべての呼び出し側に返される。