AndroidAnnotationsのプラグインを作成する

※2017年2月7日時点の公式リポジトリのWikiに記載されている[Creating an AndroidAnnotations plugin](https://github.com/androidannotations/androidannotations/wiki/Creating-an-AndroidAnnotations-plugin)の日本語訳です。

AndroidAnnotations 4.0.0から、簡単に新しいアノテーションをプラグインを作成することで追加することができるようになりました。プラグインは新しいアノテーションを追加することしかできないことに注意してください。すでに存在するものの動作を修正したり、新しいパラメーターを追加したりすることはできません。

## 構造

通常のプラグインは二つのモジュールで構成されます。AndroidAnnotations coreがそうであるように:

1. API jar。これはアノテーションを含みます。
2. プロセッサー jar。これはアノテーションを処理してコードを生成します。:
  * API jar(1.)に依存する
  * `org.androidannotations:androidannotations`に依存する

これらはあなたのビルドシステムで作ることができますが、[AndroidAnnotationsの中核のプラグインの一つ](https://github.com/androidannotations/androidannotations/tree/develop/AndroidAnnotations/androidannotations-ormlite)を参考にするとよいでしょう。

プラグインには名前を付けなければいけません。これはユニークでなければいけません。これによりクラスパスから問題なく探すことができます。

これらのモジュールには、いくつかのメタデータを含める必要があります。これによりメインのAndroidAnnotationsプロセッサーはプラグインを探して呼び出すことができます。:

* API jarの中に、`{pluginname}-api.properties`という名前のリソースを追加します。([この](https://github.com/androidannotations/androidannotations/blob/develop/AndroidAnnotations/androidannotations-ormlite/ormlite-api/src/main/resources/ormlite-api.properties)ように)
* プロセッサー jarの中に、`{pluginname}.properties`という名前のリソースを追加します。([この](https://github.com/androidannotations/androidannotations/blob/develop/AndroidAnnotations/androidannotations-ormlite/ormlite/src/main/resources/ormlite.properties)ように)

`pluginname`は実際のプラグイン名に置き換えてください。それぞれのファイルには下記の内容が必要です:

```
version=YOUR_VERSION
```

`YOUR_VERSION`は実際のプラグインのバージョンで置き換えてください。これは例えばMavenのアーティファクトのバージョンでなければなりません。

プロセッサーモジュールの中に*META-INF/services/org.androidannotations.plugin.AndroidAnnotationsPlugin*という名前でサービスディスクリプターファイルを作ります。[この](https://github.com/androidannotations/androidannotations/blob/develop/AndroidAnnotations/androidannotations-ormlite/ormlite/src/main/resources/META-INF/services/org.androidannotations.plugin.AndroidAnnotationsPlugin)ように。これは一行のプラグインクラスの名前を含んでいます:

```
com.example.YourPlugin
```

## アノテーションを作成する

apiモジュールの中でアノテーションを作成します。アノテーションのソースファイルはこのようになります:

```java
/**
 * Overrides toString() in the generated class.
 */
@Retention(RetentionPolicy.CLASS) // required
@Target(ElementType.TYPE) // this can vary per annotation
public @interface ToString {

}
```

## プロセッサーを作る

まず、プラグインのエントリーポイントクラスを作る必要があります。これは`AndroidAnnotationsPlugin`を継承します。

```java
package com.example;

import java.util.ArrayList;
import java.util.List;

import org.androidannotations.AndroidAnnotationsEnvironment;
import org.androidannotations.handler.AnnotationHandler;
import org.androidannotations.plugin.AndroidAnnotationsPlugin;

// the same class declared in the service descriptor file
public class YourPlugin extends AndroidAnnotationsPlugin {
    @Override
    public String getName() {
        return "pluginname"; // the same name used in your .properties files
    }

    @Override
    public List<AnnotationHandler<?>> getHandlers(AndroidAnnotationsEnvironment androidAnnotationEnv) {
        List<AnnotationHandler<?>> handlers = new ArrayList<>();
        handlers.add(new ToStringHandler(androidAnnotationEnv));
        // all the handlers which process your annotations
        return handlers;
    }
}
```

そして、実際のハンドラークラスを作ります。これはアノテーションの検証と処理を行います。

```java
package com.example;

import javax.lang.model.element.Element;

import org.androidannotations.AndroidAnnotationsEnvironment;
import org.androidannotations.ElementValidation;
import org.androidannotations.handler.BaseAnnotationHandler;
import org.androidannotations.holder.EComponentHolder;

import com.example.api.ToString;
import com.helger.jcodemodel.JExpr;
import com.helger.jcodemodel.JMethod;
import com.helger.jcodemodel.JMod;

public class ToStringHandler extends BaseAnnotationHandler<EComponentHolder> {

    public ToStringHandler(AndroidAnnotationsEnvironment environment) {
        super(ToString.class, environment); // this handles your @ToString annotation
    }

    @Override
    protected void validate(Element element, ElementValidation validation) {
        validatorHelper.enclosingElementHasEnhancedComponentAnnotation(element, validation);
        // the annotation only can be used in an enhanced class
    }

    @Override
    public void process(Element element, EComponentHolder holder) throws Exception {
        JMethod toString = holder.getGeneratedClass().method(JMod.PUBLIC, getClasses().STRING, "toString");

        toString.body()._return(JExpr.lit("Hello, AndroidAnnotations!"));
        toString.annotate(Override.class);

        // creates a method in the generated class:
        // @Override
        // public String toString() {
        //   return "Hello, AndroidAnnotations!";
        // }
    }
}
```

これでおしまいです！この最小のステップでこのクラスを処理できます。

```java
@EActivity
@ToString // your annotation
public class MyActivity extends Activity {

}
And you will generate this:

public class MyActivity_ extends MyActivity {

  @Override
  public String toString() {
    return "Hello, AndroidAnnotations!";
  }

  // ...
}
```

もちろん、これはただのダミーの例です。より複雑な場合はAndroidAnnotationsのソースコードを見てください。