Daggerはどうやってアノテーションからクラスを取り出しているのか

`MirroredTypeException: Attempt to access Class object for TypeMirror`とか言われてブチギレてる人向け．

---

## TL;DR
こんだけ．

```java
public static List<TypeMirror> getClassesFromAnnotation(Element element, Class<? extends Annotation> annotationType, String argName) {
  AnnotationMirror am = getAnnotationMirror(element, annotationType).get();
  AnnotationValue av = getAnnotationValue(am, argName);
  return TO_LIST_OF_TYPE.visit(av);
}

private static final AnnotationValueVisitor<ImmutableList<TypeMirror>, Void> TO_LIST_OF_TYPE = new SimpleAnnotationValueVisitor6<ImmutableList<TypeMirror>, Void>() {
  @Override
  public ImmutableList<TypeMirror> visitArray(List<? extends AnnotationValue> vals, Void aVoid) {
    return FluentIterable.from(vals).transform(new Function<AnnotationValue, TypeMirror>() {
      @Override
      public TypeMirror apply(AnnotationValue input) {
        return TO_TYPE.visit(input);
      }
    }).toList();
  }
};

private static final AnnotationValueVisitor<TypeMirror, Void> TO_TYPE = new SimpleAnnotationValueVisitor6<TypeMirror, Void>() {
  @Override
  public TypeMirror visitType(TypeMirror t, Void aVoid) {
    return t;
  }
};
```

長く見えるのはクラス名がいちいち長いからとジェネリクスのせいです．
IDEの補完があれば手間なく打てます．

static importされてるのは[common][common]の`MoreElements.getAnnotationMirror()`と`AnnotationMirrors.getAnnotationValue()`です．

### 目的

たとえばDagger使うときに書くこんなの．

```java
@Component(
  dependencies = {
    CocoaComponent.class,
    ChinoComponent.class,
    RizeComponent.class,
    ChiyaComponent.class,
    SyaroComponent.class
  }
)
public interface GochiusaComponent {
}
```

この`@Component`に渡した`dependencies`のクラスを取り出したい．

### よくある事故

`@Component`の定義は以下のようになっているはず（実際はもうちょい色々ある）．

```java
@Target(TYPE)
public @interface Component {
  Class<?>[] dependencies() default {};
  Class<?>[] modules() default {};
}
```

ここで，「じゃあふつうに`getAnnotation()`してくればいいじゃん！」となる．

```java
element.getAnnotation(Component.class).dependencies();
```

すると最初に挙げたエラーを吐いて死ぬことになる．

一応，以下のようにして`MirroredTypeException`をcatchしてあげればTypeMirrorが取り出せる．

```java
try {
  element.getAnnotation(Component.class).dependencies();
} catch(MirroredTypeException e) {
  return e.getTypeMirror();
}
```

Exception吐く前提の対応．

## [google/dagger][dagger]の場合
では，コード生成大好き企業ことGoogleさんちの[**Dagger**][dagger]はどうしているのか．
[**google/auto**][auto]というJavaでコード生成して遊ぶためのサムシングが入ったリポジトリが存在しており，Dagger compilerはその中の[**common（Auto common utilities）**][common]というライブラリをフル活用して実装されている．

本稿では[記事執筆時点での最新のmaster](https://github.com/google/dagger/tree/9293bcf0e8ddb93121dbdf74ff771a3ee9e43379)のコードを追いながら，Daggerが如何にしてアノテーションからクラスをぶっこ抜いているかを紹介する．また，[google/auto][auto]については[**auto-common-0.5**](https://github.com/google/auto/tree/auto-common-0.5)のタグを参考にする．

### 前提知識
[common][common]には[`BaseAnnotationProcessor`](https://github.com/google/auto/blob/auto-common-0.5/common/src/main/java/com/google/auto/common/BasicAnnotationProcessor.java)）というクラスが存在する．これは`AbstractProcessor`を実装しており，処理を[`ProcessingStep`](https://github.com/google/auto/blob/auto-common-0.5/common/src/main/java/com/google/auto/common/BasicAnnotationProcessor.java#L416-L427)という単位に分割してくれる．Daggerでもこれを利用している．

### ComponentProcessingStep
前述のとおり処理は複数のProcessingStepに分割されている．そのなかから今回の目的の処理をしてそうなStepである[`ComponentProcessingStep`](https://github.com/google/dagger/blob/9293bcf0e8ddb93121dbdf74ff771a3ee9e43379/compiler/src/main/java/dagger/internal/codegen/ComponentProcessingStep.java)を見ていく．
…が，DaggerのProcessingStepはすべて[`AbstractComponentProcessingStep`](https://github.com/google/dagger/blob/9293bcf0e8ddb93121dbdf74ff771a3ee9e43379/compiler/src/main/java/dagger/internal/codegen/AbstractComponentProcessingStep.java)を継承しているので，まずはそこを見てみる．
とりあえずコンストラクタを見てみるが，フィールドの初期化しかしていない．ちょっとどこ見たらいいかわからなくなりそうだが，ここでオーバーライドされた[`process()`](https://github.com/google/dagger/blob/9293bcf0e8ddb93121dbdf74ff771a3ee9e43379/compiler/src/main/java/dagger/internal/codegen/AbstractComponentProcessingStep.java#L58-L88)メソッドを見てみる．`BaseAnnotationProcessor`が呼び出すための，実際の処理を記述していくメソッドである．

```java
@Override
public final ImmutableSet<Element> process(
  SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) {
  // 省略
  for (Element element : elementsByAnnotation.get(componentAnnotation)) {
    TypeElement componentTypeElement = MoreElements.asType(element);
    try {
      if (componentElementValidator.validateComponent(componentTypeElement, messager)) {
        ComponentDescriptor componentDescriptor =
          componentDescriptorFactory.forComponent(componentTypeElement);
        // 省略
      }
    } catch (TypeNotPresentException e) {
      rejectedElements.add(componentTypeElement);
    }
  }
  return rejectedElements.build();
}
```

注目すべきは[`ComponentDescriptor$Factory#forComponent()`](https://github.com/google/dagger/blob/9293bcf0e8ddb93121dbdf74ff771a3ee9e43379/compiler/src/main/java/dagger/internal/codegen/ComponentDescriptor.java#L258-L265)．[`ComponentDescriptor`](https://github.com/google/dagger/blob/9293bcf0e8ddb93121dbdf74ff771a3ee9e43379/compiler/src/main/java/dagger/internal/codegen/ComponentDescriptor.java)…如何にもなネーミング．

### ComponentDescriptor
[`ComponentDescriptor$Factory#forComponent()`](https://github.com/google/dagger/blob/9293bcf0e8ddb93121dbdf74ff771a3ee9e43379/compiler/src/main/java/dagger/internal/codegen/ComponentDescriptor.java#L258-L265)は[`ComponentDescriptor$Factory#create()`](https://github.com/google/dagger/blob/9293bcf0e8ddb93121dbdf74ff771a3ee9e43379/compiler/src/main/java/dagger/internal/codegen/ComponentDescriptor.java#L267-L358)という非常に長いメソッドを呼び出す．このメソッドを読んでいくと[以下のようなコード](https://github.com/google/dagger/blob/9293bcf0e8ddb93121dbdf74ff771a3ee9e43379/compiler/src/main/java/dagger/internal/codegen/ComponentDescriptor.java#L296-L299)が見つかる．

```java
private ComponentDescriptor create(TypeElement componentDefinitionType, Kind kind) {
  ImmutableSet.Builder<ModuleDescriptor> modules = ImmutableSet.builder();
  for (TypeMirror moduleIncludesType : getComponentModules(componentMirror)) {
    modules.add(moduleDescriptorFactory.create(MoreTypes.asTypeElement(moduleIncludesType)));
  }
}
```

`getComponentModules()`…とてもアヤシイ．

### ConfigurationAnnotations.getComponentModules()
先ほどの`getComponentModules()`はstatic importされており，呼ばれているのは[`ConfigurationAnnotations.getComponentModules()`](https://github.com/google/dagger/blob/9293bcf0e8ddb93121dbdf74ff771a3ee9e43379/compiler/src/main/java/dagger/internal/codegen/ConfigurationAnnotations.java#L68-L73)．

```java
private static final String MODULES_ATTRIBUTE = "modules";

static ImmutableList<TypeMirror> getComponentModules(AnnotationMirror componentAnnotation) {
  checkNotNull(componentAnnotation);
  return convertClassArrayToListOfTypes(componentAnnotation, MODULES_ATTRIBUTE);
}
```

答えに近づいてきたような気がする．

### ConfigurationAnnotations.convertClassArrayToListOtTypes()

まず[ConfigurationAnnotations.convertClassArrayToListOtTypes()](https://github.com/google/dagger/blob/9293bcf0e8ddb93121dbdf74ff771a3ee9e43379/compiler/src/main/java/dagger/internal/codegen/ConfigurationAnnotations.java#L115-L118)ですが，これはVisitorにvisitしているだけ（Visitorパターンについて詳細はここでは説明しないので，知りたい方は[Java言語で学ぶデザインパターン入門][hyuki]などを参照されたい）．
[Visitorの実装](https://github.com/google/dagger/blob/9293bcf0e8ddb93121dbdf74ff771a3ee9e43379/compiler/src/main/java/dagger/internal/codegen/ConfigurationAnnotations.java#L120-L140)を読んでみる．
例外を投げるために丁寧に書かれているが，実体はここだけ．

```java
FluentIterable.from(vals)
    .transform(
        new Function<AnnotationValue, TypeMirror>() {
          @Override
          public TypeMirror apply(AnnotationValue typeValue) {
            return TO_TYPE.visit(typeValue);
          }
    })
    .toList();
```

若干RxJavaっぽい（Streamっぽい）実装，Googleが出している便利ライブラリ[Guava][guava]の`FluentIterable`．ここでは別なVisitorにvisitすることで，`AnnotationValue`から`TypeMirror`を取り出してリストにまとめている．
[呼びだされた別のVisitor](https://github.com/google/dagger/blob/9293bcf0e8ddb93121dbdf74ff771a3ee9e43379/compiler/src/main/java/dagger/internal/codegen/ConfigurationAnnotations.java#L144-L147)を見てみる．

```java
@Override
public TypeMirror visitType(TypeMirror t, Void p) {
  return t;
}
```

…ふつうに`TypeMirror`返してるだけ．これがDaggerでアノテーションからクラスを取り出す処理の全貌である（？）．

## References
* [google/dagger][dagger]
* [google/auto][auto]
  - [common][common]
* [google/guava][guava]
* [Amazon.co.jp： 増補改訂版Java言語で学ぶデザインパターン入門: 結城 浩: 本][hyuki]

[dagger]: https://github.com/google/dagger
[auto]: https://github.com/google/auto/
[common]: https://github.com/google/auto/tree/master/common
[guava]: https://github.com/google/guava
[hyuki]: http://www.amazon.co.jp/%E5%A2%97%E8%A3%9C%E6%94%B9%E8%A8%82%E7%89%88Java%E8%A8%80%E8%AA%9E%E3%81%A7%E5%AD%A6%E3%81%B6%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3%E5%85%A5%E9%96%80-%E7%B5%90%E5%9F%8E-%E6%B5%A9/dp/4797327030