Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Annotation Processing を使ってソースを生成する

Annotation Processing を使ってソースを生成する

Hiroshi Kurokawa

December 17, 2014
Tweet

More Decks by Hiroshi Kurokawa

Other Decks in Programming

Transcript

  1. Annotation Processing を使
    ってコンパイル時にソース
    を生成する
    2014-12-17 Potatotips #12
    黒川 洋 / @hydrakecat

    View Slide

  2. ある Androider の悩み
    (
    ^ω
    ^)
    ここに Android のコードがあるじゃろ?
    これをこうして...
    g
    e
    t
    L
    o
    a
    d
    e
    r
    M
    a
    n
    a
    g
    e
    r
    (
    )
    .
    i
    n
    i
    t
    L
    o
    a
    d
    e
    r
    (
    L
    O
    A
    D
    E
    R
    _
    I
    D
    _
    1
    , n
    u
    l
    l
    , n
    e
    w L
    o
    a
    d
    e
    r
    C
    a
    l
    l
    b
    a
    c
    k
    s
    <
    D
    a
    t
    a
    >
    (
    )
    {
    @
    O
    v
    e
    r
    r
    i
    d
    e
    p
    u
    b
    l
    i
    c L
    o
    a
    d
    e
    r
    <
    D
    a
    t
    a
    > o
    n
    C
    r
    e
    a
    t
    e
    L
    o
    a
    d
    e
    r
    (
    i
    n
    t i
    d
    , B
    u
    n
    d
    l
    e a
    r
    g
    s
    ) {
    r
    e
    t
    u
    r
    n n
    e
    w D
    a
    t
    a
    L
    o
    a
    d
    e
    r
    (
    )
    ;
    }
    @
    O
    v
    e
    r
    r
    i
    d
    e
    p
    u
    b
    l
    i
    c v
    o
    i
    d o
    n
    L
    o
    a
    d
    F
    i
    n
    i
    s
    h
    e
    d
    (
    L
    o
    a
    d
    e
    r
    <
    D
    a
    t
    a
    > l
    o
    a
    d
    e
    r
    , D
    a
    t
    a d
    a
    t
    a
    ) {
    o
    n
    D
    a
    t
    a
    L
    o
    a
    d
    F
    i
    n
    i
    s
    h
    e
    d
    (
    d
    a
    t
    a
    )
    ;
    }
    .
    .
    .
    }
    )
    ;
    g
    e
    t
    L
    o
    a
    d
    e
    r
    M
    a
    n
    a
    g
    e
    r
    (
    )
    .
    i
    n
    i
    t
    L
    o
    a
    d
    e
    r
    (
    L
    O
    A
    D
    E
    R
    _
    I
    D
    _
    2
    , n
    u
    l
    l
    , n
    e
    w L
    o
    a
    d
    e
    r
    C
    a
    l
    l
    b
    a
    c
    k
    s
    <
    M
    e
    s
    s
    a
    g
    e
    L
    i
    s
    t
    >
    (
    )
    {
    @
    O
    v
    e
    r
    r
    i
    d
    e
    p
    u
    b
    l
    i
    c L
    o
    a
    d
    e
    r
    <
    M
    e
    s
    s
    a
    g
    e
    L
    i
    s
    t
    > o
    n
    C
    r
    e
    a
    t
    e
    L
    o
    a
    d
    e
    r
    (
    i
    n
    t i
    d
    , B
    u
    n
    d
    l
    e a
    r
    g
    s
    ) {
    r
    e
    t
    u
    r
    n n
    e
    w M
    e
    s
    s
    a
    g
    e
    L
    i
    s
    t
    L
    o
    a
    d
    e
    r
    (
    )
    ;
    }
    @
    O
    v
    e
    r
    r
    i
    d
    e
    p
    u
    b
    l
    i
    c v
    o
    i
    d o
    n
    L
    o
    a
    d
    F
    i
    n
    i
    s
    h
    e
    d
    (
    L
    o
    a
    d
    e
    r
    <
    M
    e
    s
    s
    a
    g
    e
    L
    i
    s
    t
    > l
    o
    a
    d
    e
    r
    , M
    e
    s
    s
    a
    g
    e
    L
    i
    s
    t d
    a
    t
    a
    ) {
    o
    n
    M
    e
    s
    s
    a
    g
    e
    L
    i
    s
    t
    L
    o
    a
    d
    F
    i
    n
    i
    s
    h
    e
    d
    (
    d
    a
    t
    a
    )
    }
    .
    .
    .
    }
    )
    ;

    View Slide

  3. こうしたい!
    p
    r
    o
    t
    e
    c
    t
    e
    d v
    o
    i
    d o
    n
    C
    r
    e
    a
    t
    e
    (
    B
    u
    n
    d
    l
    e s
    a
    v
    e
    d
    I
    n
    s
    t
    a
    n
    c
    e
    S
    t
    a
    t
    e
    ) {
    s
    u
    p
    e
    r
    .
    o
    n
    C
    r
    e
    a
    t
    e
    (
    s
    a
    v
    e
    d
    I
    n
    s
    t
    a
    n
    c
    e
    S
    t
    a
    t
    e
    )
    ;
    M
    u
    l
    t
    i
    L
    o
    a
    d
    e
    r
    .
    i
    n
    j
    e
    c
    t
    (
    t
    h
    i
    s
    , L
    O
    A
    D
    E
    R
    _
    I
    D
    _
    1
    , L
    O
    A
    D
    E
    R
    _
    I
    D
    _
    2
    )
    ;
    }
    @
    O
    n
    C
    r
    e
    a
    t
    e
    L
    o
    a
    d
    e
    r
    (
    L
    O
    A
    D
    E
    R
    _
    I
    D
    _
    1
    )
    p
    u
    b
    l
    i
    c L
    o
    a
    d
    e
    r
    <
    D
    a
    t
    a
    > o
    n
    C
    r
    e
    a
    t
    e
    D
    a
    t
    a
    L
    o
    a
    d
    e
    r
    (
    i
    n
    t i
    d
    , B
    u
    n
    d
    l
    e a
    r
    g
    s
    ) { .
    .
    . }
    @
    O
    n
    L
    o
    a
    d
    F
    i
    n
    i
    s
    h
    e
    d
    (
    L
    O
    A
    D
    E
    R
    _
    I
    D
    _
    1
    )
    p
    u
    b
    l
    i
    c v
    o
    i
    d o
    n
    D
    a
    t
    a
    L
    o
    a
    d
    F
    i
    n
    i
    s
    h
    e
    d
    (
    L
    o
    a
    d
    e
    r
    <
    D
    a
    t
    a
    > l
    o
    a
    d
    e
    r
    , D
    a
    t
    a d
    a
    t
    a
    ) { .
    .
    . }
    @
    O
    n
    C
    r
    e
    a
    t
    e
    L
    o
    a
    d
    e
    r
    (
    L
    O
    A
    D
    E
    R
    _
    I
    D
    _
    2
    )
    p
    u
    b
    l
    i
    c L
    o
    a
    d
    e
    r
    <
    M
    e
    s
    s
    a
    g
    e
    L
    i
    s
    t
    > o
    n
    C
    r
    e
    a
    t
    e
    M
    e
    s
    s
    a
    g
    e
    L
    i
    s
    t
    L
    o
    a
    d
    e
    r
    (
    i
    n
    t i
    d
    , B
    u
    n
    d
    l
    e a
    r
    g
    s
    ) { .
    .
    . }
    @
    O
    n
    L
    o
    a
    d
    F
    i
    n
    i
    s
    h
    e
    d
    (
    L
    O
    A
    D
    E
    R
    _
    I
    D
    _
    2
    )
    p
    u
    b
    l
    i
    c v
    o
    i
    d o
    n
    M
    e
    s
    s
    a
    g
    e
    L
    i
    s
    t
    L
    o
    a
    d
    F
    i
    n
    i
    s
    h
    e
    d
    (
    L
    o
    a
    d
    e
    r
    <
    M
    e
    s
    s
    a
    g
    e
    L
    i
    s
    t
    > l
    o
    a
    d
    e
    r
    , M
    e
    s
    s
    a
    g
    e
    L
    i
    s
    t d
    a
    t
    a
    ) { .
    .
    .

    View Slide

  4. サンプル
    ということで、今回は annotation processing を使ってソース
    を自動生成する話をします。

    View Slide

  5. Annotation Processing
    アノテーションでアレコレやるには2通りの方法がある。
    ランタイム時
    リフレクションをバリバリ使う方法。それほど複雑にならな
    い(?)が、ランタイム時のオーバーヘッドが大きい。
    コンパイル時
    Annotation Processing を使う方法。コンパイル時にソースコ
    ードを生成するのでランタイム時のオーバーヘッドはない。
    黒魔術。Jack & Jill は未サポート。

    View Slide

  6. Annotation Processing と言えば
    モダンな DI ライブラリは、コンパイル時にソースを生成して
    いる印象。というか、Jake の好みなだけなのかも。
    Dagger
    Dagger2
    ButterKnife

    View Slide

  7. Annotation Processing
    Java SE 6 で導入されたアノテーションを javac で処理する仕
    組み。J2SE 5.0 では apt という非標準ツールがあった。
    j
    a
    v
    a
    x
    .
    a
    n
    n
    o
    t
    a
    t
    i
    o
    n
    .
    p
    r
    o
    c
    e
    s
    s
    i
    n
    g
    .
    A
    b
    s
    t
    r
    a
    c
    t
    P
    r
    o
    c
    e
    s
    s
    o
    r
    を継承したクラスを定義して、
    p
    a
    c
    k
    a
    g
    e c
    o
    m
    .
    h
    k
    u
    r
    o
    k
    a
    w
    a
    .
    m
    u
    l
    t
    i
    l
    o
    a
    d
    e
    r
    .
    i
    n
    t
    e
    r
    n
    a
    l
    ;
    p
    u
    b
    l
    i
    c c
    l
    a
    s
    s M
    u
    l
    t
    i
    L
    o
    a
    d
    e
    r
    P
    r
    o
    c
    e
    s
    s
    o
    r e
    x
    t
    e
    n
    d
    s A
    b
    s
    t
    r
    a
    c
    t
    P
    r
    o
    c
    e
    s
    s
    o
    r {
    @
    O
    v
    e
    r
    r
    i
    d
    e
    p
    u
    b
    l
    i
    c b
    o
    o
    l
    e
    a
    n p
    r
    o
    c
    e
    s
    s
    (
    S
    e
    t
    <
    ? e
    x
    t
    e
    n
    d
    s T
    y
    p
    e
    E
    l
    e
    m
    e
    n
    t
    > a
    n
    n
    o
    t
    a
    t
    i
    o
    n
    s
    , R
    o
    u
    n
    d
    E
    n
    v
    i
    r
    o
    n
    m
    e
    n
    t r
    o
    u
    n
    d
    .
    .
    .
    }
    }
    クラス名を M
    E
    T
    A
    -
    I
    N
    F
    /
    s
    e
    r
    v
    i
    c
    e
    s
    /
    j
    a
    v
    a
    x
    .
    a
    n
    n
    o
    t
    a
    t
    i
    o
    n
    .
    p
    r
    o
    c
    e
    s
    s
    i
    n
    g
    .
    P
    r
    o
    c
    e
    s
    s
    o
    r
    に書いておけば良い。
    c
    o
    m
    .
    h
    k
    u
    r
    o
    k
    a
    w
    a
    .
    m
    u
    l
    t
    i
    l
    o
    a
    d
    e
    r
    .
    i
    n
    t
    e
    r
    n
    a
    l
    .
    M
    u
    l
    t
    i
    L
    o
    a
    d
    e
    r
    P
    r
    o
    c
    e
    s
    s
    o
    r

    View Slide

  8. Android Studio での開発
    Android の JDK には、 j
    a
    v
    a
    x
    .
    a
    n
    n
    o
    t
    a
    t
    i
    o
    n
    .
    p
    r
    o
    c
    e
    s
    s
    i
    n
    g
    .
    A
    b
    s
    t
    r
    a
    c
    t
    P
    r
    o
    c
    e
    s
    s
    o
    r が含まれていない。
    従って、Processor のコードと Android のコードを同じプロジ
    ェクトで一緒に gradle ビルドすることはできない(Maven だ
    とできる?)。

    View Slide

  9. プロジェクト構成
    以下のようなプロジェクト構成にする必要がある
    multiloader
    Android ライブラリモジュー
    ル。Android アプリから呼び出
    す API を提供。
    multiloader-compiler
    Annotation Processing を行う
    コード。Android アプリには含
    まれない。
    multiloader-sample
    ライブラリを呼び出すサンプ
    ルアプリ。

    View Slide

  10. build.gradle
    b
    u
    i
    l
    d
    .
    g
    r
    a
    d
    l
    e
    には以下のように書いておく。m
    u
    l
    t
    i
    l
    o
    a
    d
    e
    r
    -
    c
    o
    m
    p
    i
    l
    e
    r が dependency に入るけれど apk に入らない、という
    状態を作るために、 を利用する。
    android-apt
    multiloader/build.gradle
    multiloader-compiler/build.gradle
    multiloader-sample/build.gradle
    a
    p
    p
    l
    y p
    l
    u
    g
    i
    n
    : '
    c
    o
    m
    .
    a
    n
    d
    r
    o
    i
    d
    .
    l
    i
    b
    r
    a
    r
    y
    '
    d
    e
    p
    e
    n
    d
    e
    n
    c
    i
    e
    s {
    c
    o
    m
    p
    i
    l
    e p
    r
    o
    j
    e
    c
    t
    (
    '
    :
    m
    u
    l
    t
    i
    l
    o
    a
    d
    e
    r
    -
    c
    o
    m
    p
    i
    l
    e
    r
    '
    )
    }
    a
    p
    p
    l
    y p
    l
    u
    g
    i
    n
    : '
    j
    a
    v
    a
    '
    a
    p
    p
    l
    y p
    l
    u
    g
    i
    n
    : '
    c
    o
    m
    .
    a
    n
    d
    r
    o
    i
    d
    .
    a
    p
    p
    l
    i
    c
    a
    t
    i
    o
    n
    '
    a
    p
    p
    l
    y p
    l
    u
    g
    i
    n
    : '
    a
    n
    d
    r
    o
    i
    d
    -
    a
    p
    t
    '
    d
    e
    p
    e
    n
    d
    e
    n
    c
    i
    e
    s {
    a
    p
    t p
    r
    o
    j
    e
    c
    t
    (
    '
    :
    m
    u
    l
    t
    i
    l
    o
    a
    d
    e
    r
    -
    c
    o
    m
    p
    i
    l
    e
    r
    '
    )
    c
    o
    m
    p
    i
    l
    e p
    r
    o
    j
    e
    c
    t
    (
    '
    :
    m
    u
    l
    t
    i
    l
    o
    a
    d
    e
    r
    '
    )
    }

    View Slide

  11. Processor の実装
    文字列連結...
    b
    u
    i
    l
    d
    e
    r
    .
    a
    p
    p
    e
    n
    d
    (
    "
    /
    / G
    e
    n
    e
    r
    a
    t
    e
    d c
    o
    d
    e f
    r
    o
    m M
    u
    l
    t
    i
    L
    o
    a
    d
    e
    r
    . D
    o n
    o
    t m
    o
    d
    i
    f
    y
    !
    \
    n
    "
    )
    ;
    b
    u
    i
    l
    d
    e
    r
    .
    a
    p
    p
    e
    n
    d
    (
    "
    p
    a
    c
    k
    a
    g
    e "
    )
    .
    a
    p
    p
    e
    n
    d
    (
    c
    l
    a
    s
    s
    P
    a
    c
    k
    a
    g
    e
    )
    .
    a
    p
    p
    e
    n
    d
    (
    "
    ;
    \
    n
    \
    n
    "
    )
    ;
    b
    u
    i
    l
    d
    e
    r
    .
    a
    p
    p
    e
    n
    d
    (
    "
    p
    u
    b
    l
    i
    c c
    l
    a
    s
    s "
    )
    .
    a
    p
    p
    e
    n
    d
    (
    c
    l
    a
    s
    s
    N
    a
    m
    e
    )
    .
    a
    p
    p
    e
    n
    d
    (
    " i
    m
    p
    l
    e
    m
    e
    n
    t
    s L
    o
    a
    d
    e
    r
    M
    a
    n
    a
    g
    e
    r
    .
    L
    o
    a
    d
    e
    b
    u
    i
    l
    d
    e
    r
    .
    a
    p
    p
    e
    n
    d
    (
    " p
    r
    i
    v
    a
    t
    e " + e
    n
    c
    l
    o
    s
    i
    n
    g
    C
    l
    a
    s
    s
    N
    a
    m
    e +
    " m
    A
    c
    t
    i
    v
    i
    t
    y
    ;
    \
    n
    "
    )
    ;
    StringBuilder じゃなくてストリームでも書けます
    プログラム構造を解析して、いろいろチェックもできます

    View Slide

  12. デモ

    View Slide

  13. まとめ
    Annotation Processing のときに構文的なもの
    (Enclosing/Enclosed)を見れるのは、おもしろい
    複雑なことはやらない方が良い
    コンパイル時にチェックできるのが、地味にうれしい
    文字列連結でソースコードを書くの、つらい
    → square/javawriter

    View Slide