techium

このブログは何かに追われないと頑張れない人たちが週一更新をノルマに技術情報を発信するブログです。もし何か調査して欲しい内容がありましたら、@kobashinG or @muchiki0226 までいただけますと気が向いたら調査するかもしれません。

Annotationを自作する

普段Androidアプリの開発を行っている際に、何の気なしにAnnotationを使用していましたが、ふとその仕組みが気になりました。

Annotationを利用することで二重化を防いだりコード量を減らせたりといった利点もありますが、個人的には使いすぎると可読性が下がるようにも感じます。 なのでその仕組みを理解して使うことは重要だと思いました。
というわけで、ちょー今更ながらAnnotationについて調査して自作してみたのでその備忘録です。

自作Annotationを定義する

今回はシンプルに以下のようにAnnotationを定義しました。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface MyAnno {

}

アノテーションは型@interfaceで宣言します(8行目) 。
後で出てきますが、今回Reflectionを利用してAnnotationが付与されたメソッドを見つけ出して実行します。ReflectionでAnnotationの情報を読み取るには@RetentionアノテーションにRetentionPolicy.RUNTIMEを指定してやる必要があります(6行目)。
Annotationを理解するための自作でAnnotationを利用するとは。
また、今回作成するAnnotationはメソッドに対して利用するため、@TargetアノテーションにElementType.METHODを指定しています(7行目) 。

アノテーションを利用する

せっかく作ったので使ってみます。
今回はAndroidで、onStartの時に宣言したメソッドが呼ばれるようにするアノテーションを作成してみます。

public class MainActivity extends BaseActivity {

    @MyAnno
    public void sampleMethod(){
        Log.d("seit", "This is Smaple Method");
    }

    @Override
    protected  Class<?> getSubClass() {
        return (Class<?>)getClass();
    }
}
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

public class BaseActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public void onStart(){
        super.onStart();

        Class clazz = getSubClass();
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            try {
                Annotation[] annotations = method.getDeclaredAnnotations();
                for (Annotation annotation : annotations) {
                    if (annotation.annotationType().equals(MyAnno.class)) {
                        Log.d("seit", "MyAnnoが宣言されたメソッドです。");
                        method.invoke(clazz.newInstance());
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    protected  Class<?> getSubClass() {
        return (Class<?>)getClass();
    }
}

MainActivityのsampleMethodメソッドに、今回自作したMyAnnoを宣言しました。
BaseActivityのonStartで、Reflectionを利用してサブクラスのメソッドを取得し、メソッドに付与されたAnnotationからMyAnnoを探しています。MyAnnoが見つかったら、Log出力を行った後に、invokeでそのメソッドを実行しています。
その結果、onStartが呼ばれたタイミングで、以下のようにログが出力されます。

D/seit: MyAnnoが宣言されたメソッドです。
D/seit: This is Smaple Method

これで、MyAnnoをメソッドに付与すればonStartの時にログが出力されるようになりました。嬉しいですね(?)

というわけで、何はともあれAnnotationの基本的な作り方がわかりました。
これを機に普段使っているAnnotationのソースコードも読んでみたいところです。