Struts1ユーザにGrailsをオススメする6の理由 - The search is over -

Struts1のEOLがアナウンスされました。 最後のリリースから長く時間が経過しており、実質開発は終了している状態でしたが、このタイミングでのアナウンスとなりました。

アナウンスの中では、次の乗り換え先として、Struts2・Spring Web MVCGrails・Stripesといったフレームワークがお薦めされていますが、私はダンチな生産性を提供するGrailsをお勧めします。

私のフレームワーク遍歴は、Struts1、WicketSeasar2、Springと色々渡り歩いてきましたが、ここ1年はがっつり業務でGrailsを使用しています。 1年がっつり使ってみた経験から、Struts1ユーザにGrailsをお勧めする理由をいくつか考えてみました。

Grailsは既存Javaフレームワークの延長線上にある

Grailsを支える基盤は、Spring・Hibernateといった、Javaの世界でよく知られ、また広く使われているフレームワークです。 ビューはSpring MVCをベースとしており、モデルはHibernateをベースとしています。 このため、既存のJavaシステムで、これらフレームワークの知識を有している場合は、そのノウハウを思う存分活用できます。

Struts1ユーザからみてGrailsをお勧めする理由の1つは、Grailsのコントローラがリクエスト駆動ベースであることです。 WicketJSFなどのように、コンポーネントベースではありません。 このため、Struts1でActionクラスを実装してしてきたユーザにとって、GrailsのControllerは非常に馴染みやすいはずです。

さらに、Java EE互換である点も重要です。 Grailsでは、単にgrails warとコマンドを実行するだけでwarファイルを生成できます。 このwarファイルは、Tomcatなど今までStrutsアプリケーションをデプロイしてきたアプリケーションサーバにデプロイ可能です。 既存のアプリケーションサーバが使用できるため、今までの運用ノウハウも引き続き活用できます。

GroovyはJava開発者のための言語である

RubyPythonといった言語に比べて、Javaコードの冗長さは、よく批判の対象になります。 Groovyの目標は、常に、このJavaの定型的な冗長さを排除し、Java開発者に異次元の生産性を提供することです。

GroovyはJava言語の延長にある、Java開発者のための言語です。 Java開発者のための言語である証拠に、一部の例外を除き、Javaのコードは、Groovyのコードとして実行可能です。 これは、Groovyのシンタックスは、Javaのシンタックスと互換があるということです。 そのため、Javaプログラマであれば、今すぐにでもGroovyのコードが書き始められます! 世界中の多くのJavaエンジニアは、潜在的なGroovyエンジニアといっても過言ではないでしょう。 若干言い過ぎたかも知れませんが、Javaエンジニアにとって非常に学びやすい言語であることは間違いありません。

もちろん、Javaコードとの親和性だけでなく、GroovyにはJava開発者に異次元の生産性を提供する多くの機能が含まれています。 型宣言の省略、クロージャ、便利なコレクション操作、メタプログラミング、演算子のオーバーロードなど、Rubyや他言語で羨ましかった機能、またはそれ以上の機能がGroovyで使用できます。

Grailsは、このGroovyでコードを書きます。 Struts1ユーザにとっては、このGroovyが逆に障壁になるかと思います。 いくらJavaとの親和性が高いとはいえ、言語が変わるというのは大きな話です。 しかし、新たなフォースを手に入れるには常に痛みが付き物です。 Java開発者にとって、比較的少ない痛みで、異次元の生産性が手に入るのはGroovy以外にありません。

既存のJava資産をそのまま活用できる

GroovyとJavaの親和性の高さも、既存のJava開発者にとって大きな魅力の1つです。 Groovyからは、既存のJavaのライブラリ・フレームワークといった、Javaのコードを簡単に呼び出すことができます。 これは、Javaのコード内でJavaのコードを呼ぶように、Groovyのコード内でJavaコードを呼び出せます。

また、GrailsでもJavaライブラリや、Javaのコードと連携する仕組みが予め用意されています。 jar形式のJavaライブラリは、単にlibディレクトリにファイルを置くだけで、簡単にアプリケーションの依存関係として追加できます。 Javaコードには、デフォルトでsrc/javaというディレクトリがGrailsによって用意されており、このディレクトリでJavaコードをすぐに書き始めることができます。

もし、Strutsアプリケーションで使用してた、ライブラリや、ビジネスロジックなどの資産がある場合は、 Grails上でもその資産を活用できます。

フレームワークの連携で悩むことはありません

Struts1を単独で使用していたユーザもいるかも知れませんが、SpringやHibernateといった、他のフレームワークと組み合わせて使用していたユーザも多くいると思います。 これらフレームワークを組み合わせて使用する場合は、自分で連携の設定をしなければなりません。 この連携の設定を調べるために、インターネットを彷徨い、気がつくと1日2日経過していた、という話は珍しくありません。 一度連携できたら、使い回すだけでしょ?と思いがちですが、フレームワークのバージョンに伴い設定方法が変更になり、また1日2日インターネットにダイブする羽目になります。

たかが数日と思うかもしれませんが、迅速な開発が求められる昨今においては、これは非常に足かせになります。ぐぐってる暇なんてありません。

Grailsフルスタックフレームワークです。create-appとコマンドを打てば、数秒で全てのフレームワーク連携が完了した雛形が手に入ります。 Struts1のように、フレームワークの連携で悩むことは、Grailsではありません。

進化し続けるフレームワーク

Struts1ユーザにとって、乗り換えたフレームワークが、数年で使い物にならなくなる自体はあまり嬉しくないでしょう。 そのため、現在Grailsの開発が活発に行われているか、今後もメンテンナスが続くかは関心の1つかと思います。

現在Grailsは、VMwareとEMCとの合併会社Pivotalの配下にある、SpringSourceで開発が行われています。 開発自体はオープンに行われており、ベンダー依存を気にする必要は今のところ無いかと思います。 ソースコードGithubで公開されています。

開発は活発に行われており、世の中の動向に合わせて新しい機能が今なお追加されています。 ただ、新しい機能がどんどん追加されているため、正直枯れているとは言えない状況です。

Sturts1ユーザにとっては、安定性が心配になるかと思いますが、商用レベルでの使用に十分耐えるレベルではあるので、安心してください。

学習環境

Grailsドキュメントは非常にしっかりと書かれており、日本語版も鋭意翻訳中です。

まとめ

GrailsJava開発者のための、フレームワークです。 Java開発者が魅力を感じないとしたら、ほんと訴求先がないと言っていいかもしれません(言語、フレームワークは素晴らしいのは間違いないのですが、Java開発者以外には訴求力が弱い)。

ということでSturts1ユーザの皆さん、一緒にGrailsやりましょう!

Mountain Lionで~/.MacOSX/environment.plistがきかない

http://d.hatena.ne.jp/y_sumida/20120805/1344134360
をみてて~/.MacOSX/environment.plistでグローバルに設定できたよなと思いつつ、ローカルの環境を確認してみるとうまく動いていない...

Mountain Lion以前までは以下の方法で回避していたのですが
https://blogs.oracle.com/katakai/entry/netbeans_and_java_for_mac2
どうもMountain Lionからは~/.MacOSX/environment.plistを広なくなった模様(前からサポート停止されてた?)。いろいろぐぐってみると/etc/launchd.confに書けとのこと。

デフォルトではファイルすら存在しないので、ファイルを作ってOS再起動。

setenv JAVA_HOME /Library/Java/JavaVirtualMachines/1.7.0.jdk/Contents/Home
setenv _JAVA_OPTIONS -Dfile.encoding=UTF-8

すると

$ groovy -version
Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8
Groovy Version: 2.0.1 JVM: 1.7.0_05 Vendor: Oracle Corporation OS: Mac OS X

_JAVA_OPTIONS拾ってくれました!Intellij IDEA上で日本語テスト名もこれで大丈夫でした。

2013年5月13日追記

http://piyopiyoducky.net/blog/2013/04/13/java-system-properties-setting-and-character-encoding/

によるとJava7からLANGの設定を拾ってくれるため/etc/launchd.confに以下のように書けば良いとのこと。

setenv LANG ja_JP.UTF-8

Spring Data JPA で遊んでみる まとめ

いろいろ紹介してきましたが、全部以下に書いてあるので、ざっと目を通すといいかなぁと思います。

http://static.springsource.org/spring-data/data-jpa/docs/current/reference/html/#repositories.custom-implementations

色々触ってみた感想は、Spring で JPA 使うなら1番目の選択肢として考えていいじゃないかと思います。

メソッドだけでクエリを定義できるといった高級な機能から、独自実装ももてるといった、幅広いカスタマイズ性も持ちあわせており、守備範囲が広く良く出来てるなぁといった印象です。

では、そんな感じで。

Spring Data JPA で遊んでみる 〜その11〜

ここまで紹介てきたクエリの発火方法で、恐らくほとんどのことができるんじゃないかと思います。ただ、どうしても自分で実装を持ちたくなるような時もあります。

Spring Data JPA では定義したリポジトリのインタフェースに対し、独自の拡張クラスを作成することができます。

まず拡張したいメソッドを定義したインタフェースを用意します。

public interface EmpRepositoryCustom {
    String echo(String message);
}

拡張メソッドだけを定義したインタフェースを個別に起こしているところに注意してください。

これをリポジトリのインタフェースに継承させます。

public interface EmpRepository extends EmpRepositoryCustom {

インタフェースの準備はこれで終わりです。実装くらすはEmpRepositoryCustomを実装しつつクラス名をリポジトリ名+Implとなるようにします。このルールは変えられますし、独自にSpringのBeanとして個別に定義することもできます。詳しくはマニュアルを参照してください。

実装クラスはこんなんです。

public class EmpRepositoryImpl implements EmpRepositoryCustom {
    @Override
    public String echo(String message) {
        return message;
    }
}

ちょっとインタフェースの定義が、独自メソッドだけ切り出してインタフェースを別に起こさないといけないなど、手間な感じが最初はしたのですが、一貫して基底となるインタフェースで、他のインタフェースを継承することで機能拡張が行えるというスタイルな感じがして、これはこれでmixinポイ感じで統一感があるのかなぁと思いました。これはJpaRepositoryを継承すればJPAの機能が、JpaSpecificationExecutorを継承すればSpecificationの機能が、QueryDslPredicateExecutorを継承すればQueryDslの機能が、独自のインタフェースを継承すれば独自の機能がという感じです。

サンプル
https://github.com/yamkazu/springdata-jpa-example/tree/customimpl

Spring Data JPA で遊んでみる 〜その9〜

昨日のSpecificationの続きでSpecificationを複数組み合わせて使う際に便利な、Specificationsというヘルパークラスが用意されている。

public class Specifications<T> implements Specification<T> {
  private final Specification<T> spec;
  private Specifications(Specification<T> spec) {...}
  public static <T> Specifications<T> where(Specification<T> spec) {...}
  public Specifications<T> and(final Specification<T> other) {...}
  public Specifications<T> or(final Specification<T> other) {...}
  public static <T> Specifications<T> not(final Specification<T> spec) {...}
  public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) {...}
}

幾つかメソッドが定義されていますがwhereを基点としてandとかorとかでつなげていく感じ。

例えば2つSpecがあるとして

public class EmpSpecifications {
    public static Specification<Emp> idLessThanOrEqualTo(final Long id) {
        return new Specification<Emp>() {
            @Override
            public Predicate toPredicate(Root<Emp> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                return cb.lessThanOrEqualTo(root.get(Emp_.id), id);
            }
        };
    }

    public static Specification<Emp> hasDept(final Dept dept) {
        return new Specification<Emp>() {
            @Override
            public Predicate toPredicate(Root<Emp> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                return cb.equal(root.get(Emp_.dept), dept);
            }
        };
    }
}

これを組み合わせて使う場合は

List<Emp> emps = repository.findAll(where(idLessThanOrEqualTo(9L)).and(hasDept(Dept.of(1L))));

とかいうふうに使えます。

サンプルこのへん。
https://github.com/yamkazu/springdata-jpa-example/tree/complexspec

Spring Data JPA で遊んでみる 〜その10〜

Spring Data JPA では Querydsl なるものがサポートされています。
http://www.querydsl.com/

色々機能があるみたいですが、カンタに言うとEntityクラスからAPTでメタ情報のクラスを生成して、そのクラスを利用してタイプセーフで流れるようにクエリが書けるようなものです。s2jdbcチックな感じです。

APTなので若干セットアップがかったるいですが。
まずpomにライブラリの追加。

    <!-- Query Dsl -->
    <dependency>
      <groupId>com.mysema.querydsl</groupId>
      <artifactId>querydsl-jpa</artifactId>
      <version>2.2.3</version>
    </dependency>
    <dependency>
      <groupId>com.mysema.querydsl</groupId>
      <artifactId>querydsl-apt</artifactId>
      <version>2.2.3</version>
      <scope>provided</scope>
    </dependency>

mavenでaptを実行するようにしておきます。

      <plugin>
        <groupId>com.mysema.maven</groupId>
        <artifactId>maven-apt-plugin</artifactId>
        <version>1.0</version>
        <executions>
          <execution>
            <phase>generate-sources</phase>
            <goals>
              <goal>process</goal>
            </goals>
            <configuration>
              <outputDirectory>target/generated-sources</outputDirectory>
              <processor>com.mysema.query.apt.jpa.JPAAnnotationProcessor</processor>
            </configuration>
          </execution>
        </executions>
      </plugin>

ついでにソースを追加するあれをいれておくとよい。

      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>build-helper-maven-plugin</artifactId>
        <executions>
          <execution>
            <id>add-source</id>
            <phase>compile</phase>
            <goals>
              <goal>add-source</goal>
            </goals>
            <configuration>
              <sources>
                <source>target/generated-sources</source>
              </sources>
            </configuration>
          </execution>
        </executions>
      </plugin>

最近はm2eの仕組みが色々と変わってEclipseで連携する場合は色々とめんどい。。。ので書きません。

良い感じにソースコードが自動生成されるようになったらリポジトリにQueryDslPredicateExecutorを継承させます。

public interface EmpRepository extends QueryDslPredicateExecutor<Emp>

QueryDslPredicateExecutorに定義されているのは以下のメソッド

T findOne(Predicate predicate);
Iterable<T> findAll(Predicate predicate);
Iterable<T> findAll(Predicate predicate, OrderSpecifier<?>... orders);
Page<T> findAll(Predicate predicate, Pageable pageable);
long count(Predicate predicate);

使うときは自動生成されたメタクラスを使用しつつクエリを組み立てて食わせます。

@Test
public void Querydslを使う() throws Exception {
    Iterable<Emp> emps = repository.findAll(QEmp.emp.id.lt(9L).and(QEmp.emp.dept.id.eq(1L)));
}

サンプルはこんなん
https://github.com/yamkazu/springdata-jpa-example/tree/querydsl