JPA2.0のタイプセーフCriteriaAPI感想とGoogle Collections Library

 今までJPA2.0のCriteriaを試してみた感想とかそこらへんを書いていこうと思います。

 結論から言うとCriteriaはJavaによるプログラミングを追求しているって感じじゃないのかなと*1

ANDやORの使い方について

 この感想を書くにはGoogle Collections Libraryで提供されているとあるAPIの事を取り上げねばならないのでまずはそちらについて。

 Google Collections Libraryにはいろんな機能があるのですが今回関係するのはPredicate、Predicates、Iterablesといったクラスです。これらを使うとJavaクロージャーを使う感じでListの絞り込みとか出来るようになります*2。ちなみにこのやり方はNext Generation Java Programing Styleの3番目に紹介されているやり方です。例えば下記はEmployeeのListから「IDが3より大きく且つAgeが18以上30以下もしくは部署がFinanceかIT」の従業員をコンソール出力するプログラムになります。(Employeeクラスは省略してます)

    public void exec(){
        //IDで絞り込むPredicate
        Predicate<Employee> byId = new Predicate<Employee>() {
            @Override
            public boolean apply(Employee input) {
                return input.getId() > 3;
            }
        };

        //18歳以上で絞り込むPredicate
        Predicate<Employee> ge18 = new Predicate<Employee>() {
            @Override
            public boolean apply(Employee input) {
                return input.getAge() >= 18;
            }
        };

        //30歳以下で絞り込むPredicate
        Predicate<Employee> le30 = new Predicate<Employee>() {
            @Override
            public boolean apply(Employee input) {
                return input.getAge() <= 30;
            }
        };

        //部署がFinanceで絞り込むPredicate
        Predicate<Employee> finance = new Predicate<Employee>() {
            @Override
            public boolean apply(Employee input) {
                return input.getDepartment().equals("Finance");
            }
        };

        //部署がITで絞り込むPredicate
        Predicate<Employee> it = new Predicate<Employee>() {
            @Override
            public boolean apply(Employee input) {
                return input.getDepartment().equals("IT");
            }
        };

        //ここでIterables.filterとPredicatesのorやandを使って絞り込む!
        for(Employee emp:Iterables.filter(getList(),Predicates.and(byId,Predicates.or(Predicates.and(ge18,le30),finance,it)))){
            System.out.println("emp = "+emp);
        }
    }

    private List<Employee> getList(){
        List<Employee> list = new ArrayList<Employee>();
        //いろんなEmployeeを作成してadd 省略・・・
        return list;
    }

最後のforの部分においてIterablesとPredicatesをstatic importすると下記のように見やすくなるかと思います。

        for(Employee emp:filter(getList(),and(byId,or(and(ge18,le30),finance,it)))){
            System.out.println("emp = "+emp);
        }

 また、これはListをプログラム上で作成してそれを絞り込んだわけですが、仮に同じ条件でDBのEMPLOYEEテーブルから取得する場合だとSQLは下記のようになります。

SELECT
    *
FROM
    EMPLOYEE 
WHERE 
    ID > 3  AND 
    (
     (AGE >=18 AND AGE <= 30) OR 
      DEPARTMENT = 'Finance' OR 
      DEPARTMENT = 'IT'
    ) 

 Google Collections Libraryとの最大の違いはANDやORの位置です。そしてこの違いは以前のエントリーでも書いたJPA2.0のCriteria APISQLでのANDやORの位置の違いと同じです(Google Collections LibraryとCriteria APIが同じ)。また、Criteria APIにてequalやorやandの戻り値となるのはPredicateという型です。
 不思議なもので自分がGoogle Collections Libraryを使用して上記のような絞り込みを試したときは始めてCriteria APIを使ったときのような違和感は感じませんでした。それでなんでなんだろうかと自分でいろいろ考えたんですが大きな理由は下記の2つになるんじゃないかという結論に達しました。

  • Googleが作ったAPIだからwww
  • 絞り込みの対象がDBのテーブルではなくListだから

 1番目は冗談としても2番目は重要だと思うんです。SQLではなくJavaのプログラミングとして考えると確かにandやorの使い方はすんなり頭に入ったわけです。JSRの中の人がどれほどGoogle Collections Libraryを意識していたのか、もしくはそれ以前からそういうプログラミングスタイルが欧米では珍しくなかったのかは不明ですがこのANDとORの使い方に関してGoogle Collections LibraryとCriteria APIが同じだという事実はCriteria APIを使うもしくは理解する上では重要なのではないでしょうか。
 また、そもそもJPAJavaにおけるO/Rマッパーの標準APIです。O/Rマッパーとは本来の意味で言うとオブジェクト指向とリレーショナルなデータ管理指向との間におけるインピーダンスミスマッチを解決するためのものです。その点で考えるとJPAのCriteria APISQL寄りではなくJava寄りになったのは当然といえば当然なのかもしれません。
 

Criteria APIを使用することで生産性は上がるのか??

 これは正直わかりませんww自分は結構慣れたので動的なSQL構築なんかはCriteriaはかなり良いと思います。ただ、id:da-yoshiさんの
GlassFish V3 b67を使ってJava Persistence 2.0を試す - TYAGE EMOTION
にて最後の方に書かれているように一時変数が多くなりがちです*3。あと、id:trygunさんのこちらのエントリー
2009-10-14
にて後輩さんが言うことはもっともだと思います。

Criteria APIは流行るのか??

 ぶっちゃけ日本では流行らないでしょうね〜。JPAHibernate利用度が高い海外であれば主流になるかもしれませんがSQLっぽさもしくは生SQL大好きな開発者が多い日本では受け入れられないと現時点では思ってます。それが悪いことだとも思いませんしねぇ。


 とりあえず自分の立ち位置としては「まぁ、使ってみる価値が無いことは無い」という感じなので引き続きCriteriaのエントリーは書いていこうかなと、そんな感じです。

*1:当たり前だ!と言われそうですがww

*2:これを使えばListをforで回す中でのif文が綺麗さっぱり無くなるので非常にお勧めです。テスタビリティも高いですし。

*3:ここらへんはラッパー作れば多少改善出きるかと思いますが