第3回 ありえる社内勉強会
 「いわががのLombok」
お前だれよ?


    twitter: @kiris

    いわなが?いわがが?
Lombokって何?


    http://projectlombok.org   
                                   created by

    Javaの冗長性を排除する為                 
                                       Roel Spilker
    のライブラリ

    「赤唐辛子」の意味

    v0.10.4

    MIT license                    
                                       Reinier Zwitserloot
Javaの冗長性って?


        こういうのとか


    class Data {
      private int value;

        public int getValue() {
          return value;
        }
        public void setValue(int value) {
          this.value = value;
        }
    }
Javaの冗長性って?


     後、こういうのとか…

    InputStream in = new InputStream(args[0]);
    try {
      ...
    } finally {
      If (in != null) in.close();
    }
Javaの冗長性って?


     他にも、こういうのとか…

    Map<String, List<String>> map =
          new HashMap<String, List<String>>();

    ...

    for(Map.Entry<String, List<String>> entry : map) {
      ...
    }
Javaの冗長性って?


     ……


    class MyClass {
      private static Log log =
          LogFactory.getLog(MyClass.class);

     private final String name;

     public MyClass(String name) {
       if (name == null) {
         throw new NullPointerException();
       }
       this.name = name;
     }

     @Override public int toString() {
       return “MyClass(name=”+ this.name +“)”;
     }
Javaの冗長性って?

 




         こうならない為のLombok!
         続きはWebで!!
冗長の何がいけないの?


    生産性が下がる

    コード量が増えて読みづらくなる

    バグが入り込む可能性がある

    死にたくなる
Lombokの導入
Lombokを入手する


    Download lombok.jar
    
        http://projectlombok.org/download.html

    Maven or Ivy
    
        http://projectlombok.org/mavenrepo/index.html
Lombokを使う


    Javac
    
        Classpathに追加

    GWT
    
        java -javaagent:lombok.jar=ECJ

    Play Framework
    
        https://github.com/aaronfreeman/play-lombok#readme

    ECJ
    
        java -javaagent:lombok.jar=ECJ 
        -Xbootclasspath/p:lombok.jar -jar ecj.jar -cp lombok.jar
LombokをIDEでも使う


    Eclipse, NetBeans なんかに対応
    
        IDEA IntelliJはまだ未対応

    java -jar lombok.jar
Lombokを試してみる
@Data


    import lombok.Data
    public @Data class DataExample {
      private final String name;
      private int count;
      private List<Object> list;
    }


    @Dataの主な機能
     
         全てのフィールドのgetter / setter の生成
     
         toString, equals, hashCodeの生成
     
         finalフィールドを引数にしたコンストラクタの生成
結果の確認(delombok)


    変換後のコードを出力
    
        java -jar lombok.jar delombok -p ${src}

    ファイルとして保存
    
        java -jar lombok.jar delombok -d ${output} ${src}

    Ant
    
        <delombok verbose="true" encoding="UTF-8" to="$
        {output}" from="${src}" />

    Maven
    
        https://github.com/awhitford/lombok.maven
@Data(変換後)


public class DataExample {
  private final String name;
  private int count;
  private List<Object> list;

    public DataExample(String name) {
      this.name = name;
    }

    public String getName() { return name; }
    public int getCount() { return count; }
    public void setCount(int count) { this.count = count; }
    @Override public String toString() { ... }
    @Override public boolean equals(Object other) { ... }
    @Override public int hashCode() { … }
}
Eclipseからも即時反映


    その場でアウトラインや補完候補に表示されます
他の機能

   @Getter / @Setter
   @Getter(lazy=true)
   @ToString
   @EqualsAndHashCode
   @NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor
   @Data
   @Cleanup
   @Synchronized
   @SneakyThrows
   @Log
   val
   @Delegate
                                           http://projectlombok.org/features/index.html
@Getter / @Setter


    Getter / Setterの自動生成

    @Dataよりも優先


    public class GetterSetterExample {
      @Getter @Setter private String name;
      @Getter(AccessLevel.PROTECTED) private int age;
    }
@Getter / @Setter(変換後)


    Getter / Setterの自動生成

    @Dataよりも優先


    public class GetterSetterExample {
      private String name;
      private int age;

        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
        protected int getAge() { return age; }
    }
@Getter(lazy=true)


    いわゆるメモ化

    サブルーチン(関数)呼び出しの結果を保持し、再利用するこ
    とで、そのサブルーチンの呼び出し毎の再計算を防ぐ
    public class GetterLazyExample {
      @Getter(lazy=true) private final double[] cached = expensive();

        private double[] expensive() { ... }
    }
@Getter(lazy=true)(変換後)


    いわゆるメモ化

    サブルーチン(関数)呼び出しの結果を保持し、再利用するこ
    とで、そのサブルーチンの呼び出し毎の再計算を防ぐ
    public class GetterLazyExample {
      public double[] getCached() { // 本当はthread-safe
        if (!this.$lombok$lazy1i) {
          this.$lombok$lazy1v = expensive();
          this.$lombok$lazy1i = true;
        }
        return this.$lombok$lazy1v;
      }

        private double[] expensive() { ... }
    }
@Cleanup


    リソースの片付けを自動で行なう
    public static void main(String[] args) throws IOException {
      @Cleanup InputStream in = new FileInputStream(args[0]);
      @Cleanup("release") MyResource resource = new MyResource();
      ...
    }
@Cleanup(変換後)


    リソースの片付けを自動で行なう
    public static void main(String[] args) throws IOException {
      InputStream in = new FileInputStream(args[0]);
      try {
        MyResource resource = new MyResource();
        try {
          ...
        } finally {
          if (resource != null) resource.release();
        }
      } finally {
        if (in != null) in.close();
      }
    }
@Synchronized


    this以外のロックオブジェクトで排他
    public class SynchronizedExample {
      private final Object readLock = new Object();

        @Synchronized private int foo() {
          return 1;
        }
        @Syncrhonized("readLock") private int bar() {
          return 2;
        }
    }
@Synchronized(変換後)


    this以外のロックオブジェクトで排他
    public class SynchronizedExample {
      private final Object $lock = new Object();
      private final Object readLock = new Object();

        private int foo() {
          synchronized($lock) { return 1; }
        }

        private int bar() {
          synchronized(readLock) { return 2; }
        }
    }
val


    ローカル変数の型宣言を省略
    public static void main(String[] args) {
      val map = new HashMap<String, List<String>>();
      ...
      for(val entry : map.entrySet()) {
        ...
      }
    }
val(変換後)


    ローカル変数の型宣言を省略
    public static void main(String[] args) {
     final Map<String, List<String>> map =
          new HashMap<String, List<String>>();

     ...

      for(final Map.Entry<String, List<String>> entry :
    map.entrySet()) {
        ...
      }
    }
etc

   @ToString
       toStringの生成
   @EqualsAndHashCode
       equalsとhachCodeの生成
   @NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor
       コンストラクタの生成
   @SneakyThrows
       チェック例外を非チェック例外のようにthrowする
   @Delegate
       移譲処理の生成
                              http://projectlombok.org/features/index.html
Lombokのメリット


    コードの冗長性の排除
    
        生産性が上がる
    
        コードの見通しを良くなる
    
        バグを埋め込む可能性を減らす
    
        心の平穏
Lombokのデメリット


    魔法に見える(not WYSIWYG)

    Lombokのバグに悩まされる可能性がある

    リファクタリング機能との衝突

    デバッグがややこしくなる
ここまでのまとめ


    LombokはJavaの冗長性を排除する

    Lombokの導入はとても簡単

    魔法には代償をともなう
Break time
Lombokの仕組み
ソースコード生成?バイトコード生成?


    いいえ、AST変換です



    JavaのASTを直接生成・変換してます
    
        ソースコード生成と違ってコードが膨れあがりません
    
        バイトコード生成と違って同じコンパイル単位のクラスか
        らも可視的です
Lombokが保持するAST


    JavacとECJの二つのASTを別々に保持

    AnnotationHandlerも各AST毎に実装する必要がある

    二つのASTを統合するためのプロジェクトも進行中
    
        https://github.com/rzwitserloot/lombok.ast
Lombokの処理の流れ
エントリーポイント


    lombok.javac.apt.Processor
    
        implements javax.annotation.processing.Processor

    lombok.eclipse.TransformEclipseAST
    
        EclipseのParserにパッチを当てて実行
        
            https://github.com/rzwitserloot/lombok.patcher
    
        OSGi ClassLoaderに注入されて実行される
AnnotationHandlerの読み込み



    プラグイン形式の読み込み

    @ProviderFor(JavacAnnotationHandler.class)
    
        used SPI(http://code.google.com/p/spi/)
        
            Service Provider Interfaceのwrapper
ASTの探索



    ASTをトラバースしてアノテーションを探索

    アノテーションが見付かったら、
    対応するAnnotationHandlerのhandleを実行する
    AnnotationVisitor
    
        Implements JavacASTVisitor
    
        独自のVisitorも定義可能
        
            @ProviderFor(JavacASTVisitor.class)
        
            HandleVal
ASTの変換



    各AnnotationHandlerや各ASTVisitorで

    変換にはJavacなどの非公開APIを直接使用
    
        com.sun.tools.javac.tree
    
        org.eclipse.jdt.internal
Lombokを拡張する
Lombokを拡張するには?


    Lombokは外からの拡張を意識して作っているわけではない

    Lombok本体を模範することで拡張することは出来る
@Perf


    メソッドの実行時間を出力
    public class PerfExample {
      @Perf
      void foo() {
        ...
      }
    }
@Perf(変換後)


    メソッドの実行時間を出力
    public class PerfExample {
      void foo() {
        long $start = System.nanoTime();
        try {
            …
        } finally {
          System.out.println(“PerfExample.foo = ”+
              System.nanoTime() - $start));
        }
      }
    }
プロジェクトの作り方


    prototype: https://github.com/alexruiz/dw-lombok
    
        プロジェクト名などを置換
    
        Ivyの設定を一部変更
        
            ECJのjarが取得出来なかった
        
            Lombokの最新(0.10.4)を使いたかった
アノテーションの定義


    トリガーとなるPerfアノテーションを作成する
    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.SOURCE)
    public @interface Perf {
    }
AnnotationHandlerの作成


    Javac用とECJ用の二つのAnnotationHandlerを作成する
    // for javac
    package localhost.javac.handlers;

    @ProviderFor(JavacAnnotationHandler.class)
    public class HandlePerf extends JavacAnnotationHandler<Perf> {
      @Override
      public void handle(AnnotationValues<Perf> annotation,
          JCAnnotation ast, JavacNode annotationNode) {
        ...
      }
    }
AST変換処理の実装


    愚直にASTを作るだけの簡単なお仕事
    TreeMaker maker = methodNode.getTreeMaker();

    // long $start = long t1 = System.nanoTime();
    Name startName = methodNode.toName("$start");
    JCExpression nanoTimeMethod =
        chainDotsString(methodNode, "System.nanoTime");
    JCExpression nanoTimeApply =
        maker.Apply(List.<JCExpression>nil(), nanoTimeMethod,
        List.<JCExpression>nil());

    JCVariableDecl startDef =
        setGeneratedBy(maker.VarDef(maker.Modifiers(0), startName,
        maker.TypeIdent(getCtcInt(TypeTags.class, "LONG")),
        nanoTimeApply), ast);
テスト


    本体が用意しているテスト・インフラがそのまま使える
    @RunWith(DirectoryRunner.class)
    public class TestWithEcj implements TestParams {
      @Override public Compiler getCompiler() { return ECJ; }
      @Override public boolean printErrors() { return true; }

        @Override public File getBeforeDirectory() {
          return new File("test/transform/resource/before");
        }
        @Override public File getAfterDirectory() {
          return new File("test/transform/resource/after-ecj");
        }
        ...
    }
拡張されたLombokの実行


    jar化してClasspathに追加すれば良い
    $ ant dist
    $ javac -cp “.:lib/build/lombok.jar:dist/lombok-perf.jar”
    Example.java
    $ java -cp “.”Example
感想


    変換処理はわりと愚直にAST作るだけの簡単なお仕事

    本体のコードこそが最高のサンプル
    
        https://github.com/rzwitserloot/lombok/tree/master/src/co
    
        https://github.com/rzwitserloot/lombok/tree/master/src/co
まとめ


    Lombokは皆さんのJava嫌いをちょっとだけ癒してくれます



    きっとScalaプログラマにもなれないJavaプログラマの皆さん

    Lombokを手にいれてみませんか?
第三回ありえる社内勉強会 「いわががのLombok」

第三回ありえる社内勉強会 「いわががのLombok」

  • 1.
  • 2.
    お前だれよ?  twitter: @kiris  いわなが?いわがが?
  • 3.
    Lombokって何?  http://projectlombok.org  created by  Javaの冗長性を排除する為  Roel Spilker のライブラリ  「赤唐辛子」の意味  v0.10.4  MIT license  Reinier Zwitserloot
  • 4.
    Javaの冗長性って?  こういうのとか class Data { private int value; public int getValue() { return value; } public void setValue(int value) { this.value = value; } }
  • 5.
    Javaの冗長性って?  後、こういうのとか… InputStream in = new InputStream(args[0]); try { ... } finally { If (in != null) in.close(); }
  • 6.
    Javaの冗長性って?  他にも、こういうのとか… Map<String, List<String>> map = new HashMap<String, List<String>>(); ... for(Map.Entry<String, List<String>> entry : map) { ... }
  • 7.
    Javaの冗長性って?  …… class MyClass { private static Log log = LogFactory.getLog(MyClass.class); private final String name; public MyClass(String name) { if (name == null) { throw new NullPointerException(); } this.name = name; } @Override public int toString() { return “MyClass(name=”+ this.name +“)”; }
  • 8.
    Javaの冗長性って?   こうならない為のLombok! 続きはWebで!!
  • 9.
    冗長の何がいけないの?  生産性が下がる  コード量が増えて読みづらくなる  バグが入り込む可能性がある  死にたくなる
  • 10.
  • 11.
    Lombokを入手する  Download lombok.jar  http://projectlombok.org/download.html  Maven or Ivy  http://projectlombok.org/mavenrepo/index.html
  • 12.
    Lombokを使う  Javac  Classpathに追加  GWT  java -javaagent:lombok.jar=ECJ  Play Framework  https://github.com/aaronfreeman/play-lombok#readme  ECJ  java -javaagent:lombok.jar=ECJ -Xbootclasspath/p:lombok.jar -jar ecj.jar -cp lombok.jar
  • 13.
    LombokをIDEでも使う  Eclipse, NetBeans なんかに対応  IDEA IntelliJはまだ未対応  java -jar lombok.jar
  • 14.
  • 15.
    @Data import lombok.Data public @Data class DataExample { private final String name; private int count; private List<Object> list; }  @Dataの主な機能  全てのフィールドのgetter / setter の生成  toString, equals, hashCodeの生成  finalフィールドを引数にしたコンストラクタの生成
  • 16.
    結果の確認(delombok)  変換後のコードを出力  java -jar lombok.jar delombok -p ${src}  ファイルとして保存  java -jar lombok.jar delombok -d ${output} ${src}  Ant  <delombok verbose="true" encoding="UTF-8" to="$ {output}" from="${src}" />  Maven  https://github.com/awhitford/lombok.maven
  • 17.
    @Data(変換後) public class DataExample{ private final String name; private int count; private List<Object> list; public DataExample(String name) { this.name = name; } public String getName() { return name; } public int getCount() { return count; } public void setCount(int count) { this.count = count; } @Override public String toString() { ... } @Override public boolean equals(Object other) { ... } @Override public int hashCode() { … } }
  • 18.
    Eclipseからも即時反映  その場でアウトラインや補完候補に表示されます
  • 19.
    他の機能  @Getter / @Setter  @Getter(lazy=true)  @ToString  @EqualsAndHashCode  @NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor  @Data  @Cleanup  @Synchronized  @SneakyThrows  @Log  val  @Delegate http://projectlombok.org/features/index.html
  • 20.
    @Getter / @Setter  Getter / Setterの自動生成  @Dataよりも優先 public class GetterSetterExample { @Getter @Setter private String name; @Getter(AccessLevel.PROTECTED) private int age; }
  • 21.
    @Getter / @Setter(変換後)  Getter / Setterの自動生成  @Dataよりも優先 public class GetterSetterExample { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } protected int getAge() { return age; } }
  • 22.
    @Getter(lazy=true)  いわゆるメモ化  サブルーチン(関数)呼び出しの結果を保持し、再利用するこ とで、そのサブルーチンの呼び出し毎の再計算を防ぐ public class GetterLazyExample { @Getter(lazy=true) private final double[] cached = expensive(); private double[] expensive() { ... } }
  • 23.
    @Getter(lazy=true)(変換後)  いわゆるメモ化  サブルーチン(関数)呼び出しの結果を保持し、再利用するこ とで、そのサブルーチンの呼び出し毎の再計算を防ぐ public class GetterLazyExample { public double[] getCached() { // 本当はthread-safe if (!this.$lombok$lazy1i) { this.$lombok$lazy1v = expensive(); this.$lombok$lazy1i = true; } return this.$lombok$lazy1v; } private double[] expensive() { ... } }
  • 24.
    @Cleanup  リソースの片付けを自動で行なう public static void main(String[] args) throws IOException { @Cleanup InputStream in = new FileInputStream(args[0]); @Cleanup("release") MyResource resource = new MyResource(); ... }
  • 25.
    @Cleanup(変換後)  リソースの片付けを自動で行なう public static void main(String[] args) throws IOException { InputStream in = new FileInputStream(args[0]); try { MyResource resource = new MyResource(); try { ... } finally { if (resource != null) resource.release(); } } finally { if (in != null) in.close(); } }
  • 26.
    @Synchronized  this以外のロックオブジェクトで排他 public class SynchronizedExample { private final Object readLock = new Object(); @Synchronized private int foo() { return 1; } @Syncrhonized("readLock") private int bar() { return 2; } }
  • 27.
    @Synchronized(変換後)  this以外のロックオブジェクトで排他 public class SynchronizedExample { private final Object $lock = new Object(); private final Object readLock = new Object(); private int foo() { synchronized($lock) { return 1; } } private int bar() { synchronized(readLock) { return 2; } } }
  • 28.
    val  ローカル変数の型宣言を省略 public static void main(String[] args) { val map = new HashMap<String, List<String>>(); ... for(val entry : map.entrySet()) { ... } }
  • 29.
    val(変換後)  ローカル変数の型宣言を省略 public static void main(String[] args) { final Map<String, List<String>> map = new HashMap<String, List<String>>(); ... for(final Map.Entry<String, List<String>> entry : map.entrySet()) { ... } }
  • 30.
    etc  @ToString  toStringの生成  @EqualsAndHashCode  equalsとhachCodeの生成  @NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor  コンストラクタの生成  @SneakyThrows  チェック例外を非チェック例外のようにthrowする  @Delegate  移譲処理の生成 http://projectlombok.org/features/index.html
  • 31.
    Lombokのメリット  コードの冗長性の排除  生産性が上がる  コードの見通しを良くなる  バグを埋め込む可能性を減らす  心の平穏
  • 32.
    Lombokのデメリット  魔法に見える(not WYSIWYG)  Lombokのバグに悩まされる可能性がある  リファクタリング機能との衝突  デバッグがややこしくなる
  • 33.
    ここまでのまとめ  LombokはJavaの冗長性を排除する  Lombokの導入はとても簡単  魔法には代償をともなう
  • 34.
  • 35.
  • 36.
    ソースコード生成?バイトコード生成?  いいえ、AST変換です  JavaのASTを直接生成・変換してます  ソースコード生成と違ってコードが膨れあがりません  バイトコード生成と違って同じコンパイル単位のクラスか らも可視的です
  • 37.
    Lombokが保持するAST  JavacとECJの二つのASTを別々に保持  AnnotationHandlerも各AST毎に実装する必要がある  二つのASTを統合するためのプロジェクトも進行中  https://github.com/rzwitserloot/lombok.ast
  • 38.
  • 39.
    エントリーポイント  lombok.javac.apt.Processor  implements javax.annotation.processing.Processor  lombok.eclipse.TransformEclipseAST  EclipseのParserにパッチを当てて実行  https://github.com/rzwitserloot/lombok.patcher  OSGi ClassLoaderに注入されて実行される
  • 40.
    AnnotationHandlerの読み込み  プラグイン形式の読み込み  @ProviderFor(JavacAnnotationHandler.class)  used SPI(http://code.google.com/p/spi/)  Service Provider Interfaceのwrapper
  • 41.
    ASTの探索  ASTをトラバースしてアノテーションを探索  アノテーションが見付かったら、 対応するAnnotationHandlerのhandleを実行する AnnotationVisitor  Implements JavacASTVisitor  独自のVisitorも定義可能  @ProviderFor(JavacASTVisitor.class)  HandleVal
  • 42.
    ASTの変換  各AnnotationHandlerや各ASTVisitorで  変換にはJavacなどの非公開APIを直接使用  com.sun.tools.javac.tree  org.eclipse.jdt.internal
  • 43.
  • 44.
    Lombokを拡張するには?  Lombokは外からの拡張を意識して作っているわけではない  Lombok本体を模範することで拡張することは出来る
  • 45.
    @Perf  メソッドの実行時間を出力 public class PerfExample { @Perf void foo() { ... } }
  • 46.
    @Perf(変換後)  メソッドの実行時間を出力 public class PerfExample { void foo() { long $start = System.nanoTime(); try { … } finally { System.out.println(“PerfExample.foo = ”+ System.nanoTime() - $start)); } } }
  • 47.
    プロジェクトの作り方  prototype: https://github.com/alexruiz/dw-lombok  プロジェクト名などを置換  Ivyの設定を一部変更  ECJのjarが取得出来なかった  Lombokの最新(0.10.4)を使いたかった
  • 48.
    アノテーションの定義  トリガーとなるPerfアノテーションを作成する @Target({ElementType.METHOD}) @Retention(RetentionPolicy.SOURCE) public @interface Perf { }
  • 49.
    AnnotationHandlerの作成  Javac用とECJ用の二つのAnnotationHandlerを作成する // for javac package localhost.javac.handlers; @ProviderFor(JavacAnnotationHandler.class) public class HandlePerf extends JavacAnnotationHandler<Perf> { @Override public void handle(AnnotationValues<Perf> annotation, JCAnnotation ast, JavacNode annotationNode) { ... } }
  • 50.
    AST変換処理の実装  愚直にASTを作るだけの簡単なお仕事 TreeMaker maker = methodNode.getTreeMaker(); // long $start = long t1 = System.nanoTime(); Name startName = methodNode.toName("$start"); JCExpression nanoTimeMethod = chainDotsString(methodNode, "System.nanoTime"); JCExpression nanoTimeApply = maker.Apply(List.<JCExpression>nil(), nanoTimeMethod, List.<JCExpression>nil()); JCVariableDecl startDef = setGeneratedBy(maker.VarDef(maker.Modifiers(0), startName, maker.TypeIdent(getCtcInt(TypeTags.class, "LONG")), nanoTimeApply), ast);
  • 51.
    テスト  本体が用意しているテスト・インフラがそのまま使える @RunWith(DirectoryRunner.class) public class TestWithEcj implements TestParams { @Override public Compiler getCompiler() { return ECJ; } @Override public boolean printErrors() { return true; } @Override public File getBeforeDirectory() { return new File("test/transform/resource/before"); } @Override public File getAfterDirectory() { return new File("test/transform/resource/after-ecj"); } ... }
  • 52.
    拡張されたLombokの実行  jar化してClasspathに追加すれば良い $ ant dist $ javac -cp “.:lib/build/lombok.jar:dist/lombok-perf.jar” Example.java $ java -cp “.”Example
  • 53.
    感想  変換処理はわりと愚直にAST作るだけの簡単なお仕事  本体のコードこそが最高のサンプル  https://github.com/rzwitserloot/lombok/tree/master/src/co  https://github.com/rzwitserloot/lombok/tree/master/src/co
  • 54.
    まとめ  Lombokは皆さんのJava嫌いをちょっとだけ癒してくれます  きっとScalaプログラマにもなれないJavaプログラマの皆さん Lombokを手にいれてみませんか?