mattak's blog

人生を1ミリ進める

AndroidのLogを改良しよう2

Unityで遊ぼうかと思ったけど、需要ありそうな気がするのでこっち優先する. 今日は、javaソースコードレベルのアノテーションを調べて実験してみる。

RetentionPolicy.SOURCE

javaアノテーションを記述する際にリテンションポリシーを3種設定することができる。

  • RetentionPolicy.CLASS
    • デフォルトで指定される。classファイルには含まれるが、vmにロードされるときには棄却される
  • RetentionPolicy.RUNTIME
    • 実行時にも参照が可能。classファイルにも、vmロード時にも入っている.
  • RetentionPolicy.SOURCE
    • classファイルにも含まれない。classファイル生成時にか参照できない.

RetentionPolicy.SOURCE < RetentionPolicy.CLASS < RetensionPolicy.RUNTIMEの順で強度の強いアノテーションとなる.

今回目指すのは、Lombokのような@Getter @Setterとうつだけで、getter/setterのソースコードが生成されるようなタイプ. つまりRetentionPolicy.SOURCEを用いる。

参考: - http://docs.oracle.com/javase/7/docs/api/java/lang/annotation/RetentionPolicy.html

AbstractProcessor

javaでAnnotationからソースを生成するには、AbstractProcessorを利用するようだ.

以下のような構成.

lib
├── build.gradle
└── src
    └── main
        ├── AndroidManifest.xml
        ├── java
        │   └── me
        │       └── mattak
        │           └── footprint
        │               ├── Footprint.java
        │               └── processor
        │                   └── FootprintProcessor.java
        └── resources
            └── META-INF
                └── services
                    └── javax.annotation.processing.Processor

ポイントは, resources/META-INF/services/javax.annotation.processing.ProcessorにAbstractProcessorを継承したProcessorの場所を記述することらしい。

javax.annotation.processing.Processor

me.mattak.footprint.processor.FootprintProcessor

ためしにProcessor内で何か出力してみる.

@SupportedSourceVersion(SourceVersion.RELEASE_6)
@SupportedAnnotationTypes({"*"})
public class FootprintProcessor extends AbstractProcessor {
    @Override
    public boolean process(Set<? extends TypeElement> annotations,
                           RoundEnvironment roundEnv) {

        Messager messager = processingEnv.getMessager();
        for (TypeElement te : annotations) {
            for (Element e : roundEnv.getElementsAnnotatedWith(te)) {
                messager.printMessage(Diagnostic.Kind.NOTE, "Printing: " + e.toString());
                System.out.println("[annotation] " + e + "," + annotations);
            }
        }

        return true;
    }
}

このプロジェクトをimportしてなにかannotationをつけてみると、きちんとメッセージが出力された。

$ gradle clean assemble                                                                                        ~/project/Footprint [master]
Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8
Relying on packaging to define the extension of the main artifact has been deprecated and is scheduled to be removed in Gradle 2.0
:example:clean
:lib:clean
:example:compileDebugNdk
:example:preBuild
:example:preDebugBuild
:example:checkDebugManifest
:example:preReleaseBuild
:lib:compileJava
:lib:processResources
:lib:classes
:lib:jar
:example:prepareComAndroidSupportAppcompatV71800Library
:example:prepareDebugDependencies
:example:compileDebugAidl
:example:compileDebugRenderscript
:example:generateDebugBuildConfig
:example:mergeDebugAssets
:example:generateDebugResValues UP-TO-DATE
:example:generateDebugResources
:example:mergeDebugResources
:example:processDebugManifest
:example:processDebugResources
:example:generateDebugSources
:example:compileDebugJava
注:Printing: me.mattak.footprint.example.MainActivity
[annotation] me.mattak.footprint.example.MainActivity,[me.mattak.footprint.Footprint]
注:Printing: me.mattak.footprint.example.TestFile
[annotation] me.mattak.footprint.example.TestFile,[me.mattak.footprint.Footprint]
:example:preDexDebug
Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8
Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8
Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8
:example:dexDebug
Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8
:example:processDebugJavaRes UP-TO-DATE
:example:validateDebugSigning
:example:packageDebug
:example:assembleDebug
:example:checkReleaseManifest
:example:prepareReleaseDependencies
:example:compileReleaseAidl
:example:compileReleaseRenderscript
:example:generateReleaseBuildConfig
:example:mergeReleaseAssets
:example:generateReleaseResValues UP-TO-DATE
:example:generateReleaseResources
:example:mergeReleaseResources
:example:processReleaseManifest
:example:processReleaseResources
:example:generateReleaseSources
:example:compileReleaseJava
注:Printing: me.mattak.footprint.example.MainActivity
[annotation] me.mattak.footprint.example.MainActivity,[me.mattak.footprint.Footprint]
注:Printing: me.mattak.footprint.example.TestFile
[annotation] me.mattak.footprint.example.TestFile,[me.mattak.footprint.Footprint]
:example:lintVitalRelease
:example:compileReleaseNdk
:example:preDexRelease
Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8
Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8
Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8
:example:dexRelease
Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8
:example:processReleaseJavaRes UP-TO-DATE
:example:packageRelease
:example:assembleRelease
:example:assemble
:lib:assemble

BUILD SUCCESSFUL

Total time: 51.852 secs

とりあえず、RetentionPolicy.SOURCEのannotationの作用確認ができた。 ここから、元ソースにどうやってコードを介入させるのかよくわからんので、また調べて書く。