Dagger2はJavaアプリ開発に使えないのか?

Dagger2がわからない

Guiceを長年使っているのだが、改めてDIライブラリまわりの状況がどうなっているのかを知りたいと調べてみると、Dagger2というのが見つかったのだが。。。しかし、これは使えない。使い方がわからない。さんざん検索してみてわかったことは以下だ。

  • Guiceのように実行時にリフレクションを使うものではなく、事前にコード生成するものらしい。
  • Android開発者しか使っていないらしい。
  • Dagger2の欠点を述べている者がいない。
  • サンプルとして提示されているものはAndroid専用か、もしくはただのスニペットだけ。

特に最後の点が問題だ。こちらはAndroid開発などしないので、ごく普通のJavaアプリのサンプルが欲しいのだが、全く見つからない。かといって、コードスニペットを提示されたところで、それをどうするのかさっぱりわからない。

このため、一度も動かしてはいない。これ以上探すのも面倒なので。

Guiceのサンプル

Guiceのサンプルならとても簡単だ(Eclipseでの実行を前提にしている)。

build.gradle

apply plugin: 'java'
apply plugin: 'eclipse'
sourceSets {
  main {
    java {
      srcDir 'src'
    }
  }
}
repositories {
  jcenter()
}
dependencies {
  compile group: 'com.google.inject', name: 'guice', version: '4.2.2'
}

Main.java

import com.google.inject.*;
public class Main {  
  public static class Foo {
    int a = 123;
  }

  @Inject Foo foo;

  void execute() {
    System.out.println(foo.a);
  }

  public static void main(String[]args) {
    Guice.createInjector().getInstance(Main.class).execute();
  }
}

これだけで依存性注入の経験は可能だ。しかしDagger2にはこの程度のサンプルも見つけられない。

Daggerに文句を言ってる人

さらに検索してみると、Daggerに文句を言ってる人がいた。Dagger vs. Guiceである。以下要点を書いてみる。

苦痛な点

何がどこに注入できるかといういくつかの制限がある。ほとんどの場合、これらの制限は良いことであり、それはコードの改善を示している。しかし、いくつかのケースでは、あまりに制限が大きいと感じる。

注入されるオブジェクトは必ずコンストラクタに@Injectが必要

Guiceはなくてもできる。これはサードパーティのライブラリを使う場合に非常に便利だ。もちろん、自身のコードだけならOKだが。

Daggerを使う場合にはボイラープレートコードをたくさん書かないと行けなくなる。

インターフェースを実装にバインドするショートカットがない

Guiceにはあるのだが、これは製品とテストでバインディングを変更するのにとても便利だ。Daggerにはそれがない。そのためにやはりボイラープレートコードが必要になる。

制限につぐ制限

Guiceには無い制限がたくさんある。もしGuiceをつかっているなら、以下にぶち当たるだろう。

  • モジュールはabstractやprivateにできない。
  • @Providesメソッドはstatiicにできない。
  • privateやfinalメンバーに注入できない。
  • 例外を発生するコンストラクタを注入できない。

ユニットテストへの注入

Guiceでは簡単にできるが、Daggerではモジュールをつくらないといけない。つまり、テスト自身のモジュールが必要になる。

その結果テスト全体にわたってたくさんのボイラープレートコードが必要になる。

結論

一度たりとも使ってはいないのだが、面倒そうなのでパスすることにした。

そもそも、アノテーションを処理して事前にコード生成する点自体が疑問だらけだ。もちろんGuiceよりはるかに高速になるだろうが、Guiceより制限が多いことは容易に想像できる。