Java EE 7 徹底入門と初執筆について

この記事は「Java EE Advent Calendar 2015 - Qiita」の14日目のエントリーです。
昨日は@kabaoさんで、「Javaバッチの実行環境 EEなのかSEなのか」でした。
明日はaf-not-foundさんです。


本日は、明日(12/15)刊行となるJava EE 7 徹底入門についての紹介と、私がその初執筆で感じた事について書きたいと思います。

とうとう出るよJava EE 7 徹底入門!

私が執筆を一部担当させていただいたJava EE 7 徹底入門という本が明日!(12/15)発売になります。


Java EE 7徹底入門 標準Javaフレームワークによる高信頼性Webシステムの構築

Java EE 7徹底入門 標準Javaフレームワークによる高信頼性Webシステムの構築


「とうとう」と書いたのは、この書籍の話をいただいたのが2014年10月ですので、かれこれ1年以上かかった事になります。長かったー(>_<)!


本書は、日頃Javaコンサルタントをしているメンバーで、Java EEを始めて学ぶ方、またはこれから開発をJava EEに移行しようと考えているアーキテクトの方を対象にJava EEの全体像を理解してもらうことを目的に書きました。全体像とは言ってもJava EE 7の全仕様を満たしたものではなく、その中で重要だと思われるJSF,EJB,CDI,JPA,JAX-RS,JBatchについて詳細に解説しています。各章立ては以下のようになっています。(全10章)


Chapter 1 Java EEの基礎知識
Chapter 2 プレゼンテーション層の開発――JSFの基本
Chapter 3 プレゼンテーション層の開発――JSFの応用 その1
Chapter 4 プレゼンテーション層の開発――JSFの応用 その2
Chapter 5 ビジネスロジック層の開発――CDIの利用
Chapter 6 ビジネスロジック層の開発――EJBの利用
Chapter 7 データアクセス層の開発――JPAの基本
Chapter 8 データアクセス層の開発――JPAの応用
Chapter 9 RESTful Webサービスの開発
Chapter10 バッチアプリケーションの開発


私が担当したのは2〜4章のJSFの部分です。Java EE 7の仕様は膨大で、一冊の本にすべて収めることは困難です。今回は本全体を通して簡単なサンプルアプリを1つ作成し、その中で利用可能なアーキテクチャを中心に説明するという方針をとりました。(JSFの章については使用していない機能もけっこう突っ込んで記載してしまいましたが...)


JSFの2〜4章でだいたい150ページくらいでしょうか。当初の予定では80ページくらいに抑える予定でしたが、書きたいことを書き切ったら結局1章分増えてしまいました。なるべくノウハウなども詰め込んで記載したつもりなので、これからJava EEを始める方の参考になればと思っています。

執筆ってどうなの?初執筆で感じた感想

今回の「Java EE 7 徹底入門」は私にとって初めての執筆でした。当初は執筆に興味はありましたがどのようなスケジュールで刊行まで進むのか全くわからず、興味半分、不安半分という感じでした。

思っていた通り大変でした

想定はしていましたが予想通り大変でした。今回の執筆はプライベートでの執筆なので土日を使って作業しましたが、計算では150ページの本を書こうとすると本のサイズにもよるらしいですが本書だとだいたい1ページ1000文字くらい必要になります。だいたい1日頑張っても10000文字くらい書けるかどうかという感じなので2ヶ月近いの土日がすべてなくなってしまいます。実際は1日そんなに書くことはできず「数時間検証作業をして、15分記載」のような繰り返しが続くのでさらに時間を割いたと思います。特に妻子持ちの私としては土日が潰れると家族の不満もたまってくるのでそのバランスを取るのもとても大変でした。

想定外にかかるその他の作業

文章の校正作業というのをまったく意識していませんでしたが、かなり時間がかかりました。レビューの指摘で1項まるまる書き直したり、自分の書いた章を校正するだけでも一字一句丁寧に確認する必要があるので150ページあると普通に1日かかったりしていました。(校正作業中は書き過ぎたのをかなり後悔していました)またサンプルコードの整理や、章と流れをあわせるために他の章も一通り目を通すなど想定外の作業がけっこうありました。

なんだかんだで良い経験となりました

振り返ると大変さしか思い出しませんが、結果として大変多くの新しい経験と知識を得ることができてとても良い経験となりました。このような機会をいただけてとても感謝しています。ありがとうございました。


Java EEをこれからはじめたいと思う方は是非「Java EE 7 徹底入門」を手にとっていただければと思います。


Java EE 7徹底入門 標準Javaフレームワークによる高信頼性Webシステムの構築

Java EE 7徹底入門 標準Javaフレームワークによる高信頼性Webシステムの構築

JSFのバリデーション

この記事は「Java EE Advent Calendar 2014」の22日目のエントリーです。
昨日は@suke_masaさんの「続・JPQLでハマった話」でした。明日は@kikutaro_さんです。


今日はJSFのバリデーションについて整理したいと思います。

JSF1.*時代のバリデーション

JSF1.*の時代にはFaceletsのValidateタグを使用してバリデーションを行っていました。例えば5文字以上10文字以下の文字数のチェックを行うプログラムは以下です。

・facelets

<h:form>
  <div>
    <h:inputText id="msg" value="#{hogeBean.msg}">
        <f:validateLength minimum="5" maximum="10" />
    </h:inputText>
    <h:message for="msg" />
  </div>
  <h:commandButton action="#{hogeBean.exec}" value="Exec" />
</h:form>

初期のJSFは画面の作成をGUIで行っていました。そのためバリデーションの設定も画面に持つ事でプロパティで簡単に設定を行う事ができました。

JSF2.0以降のバリデーション

Java EE 6に導入されたJSF2.0からはバリデーションにBean Validationが使えるようになりました。Bean Validationを使用することでJPA等のバックグランドのチェック処理とJSFのチェック処理を共通化出来ます。Bean Validationのチェックは画面側では行わずEL式で紐づくバッキングビーン側のフィールドにアノテーションで設定します。

・バッキングビーン

@Named
@RequestScoped
public class HogeBean {
    @Size(min = 5, max = 10)
    private String msg = "Hello!";
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
    public void exec() {
    }
}

JSF2.0からは設定より規約が重視されるようになり、GUIに頼らずコードベースで簡単に開発出来るようになりました。そのため、特に画面側にバリデーションを持つ必要性は無くなりました。

Bean Validationでnullチェック出来ない問題

JSFのチェックをBean Validationで行うとすると最初に@NotNullが使用出来ないという問題に遭遇します。具体的には以下のようなソースでは未入力チェックが出来ません。

・バッキングビーン

public class HogeBean {
    @NotNull //未入力チェック出来ない
    private String msg = "Hello!";

これは画面の入力項目がnullではなく空文字として設定されるため発生します。

対処法1 空文字対応のチェックアノテーションを使用する

対処法の1つ目は@NotNullではなく空文字にも対応したアノテーションを使用する事です。たとえばHibernate Validatorで提供されている@NotEmptyを使用すると空文字の場合もエラーにする事が出来ます。

・バッキングビーン

public class HogeBean {
    @NotEmpty //未入力チェック出来できる!
    private String msg = "Hello!";

ただし、@NotEmptyを使用するとJava EE標準ではない実装アノテーションにソースが依存する事になります。

対処法2 INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULLを指定する

web.xmlのコンテキストパラメータにINTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULLを設定すると、サブミットされた値が空文字であった場合に,JSF内でnullに変換してくれます。そうする事で@NotNullで未入力のチェックを行う事が出来ます。

・web.xml

<context-param>
    <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
    <param-value>true</param-value>
</context-param>

・バッキングビーン(@NotNullのまま)

public class HogeBean {
    @NotNull //未入力チェック出来きる!
    private String msg = "Hello!";

相関チェック

JPAではエンティティを引数に渡すと設定してあるチェックは一通り実施してくれますが、JSFではEL式でフィールド単位に紐付けを行うため単項目チェックしか実施されません。対処法はいくつかありますが、今回はBean Validationで2つの項目が同じ値でないとエラーとなるバリデーションを作成してみます。

・Bean Validation用アノテーション

@Documented
@Constraint(validatedBy = {EqualsValidator.class})
@Target({FIELD})
@Retention(RUNTIME)
public @interface Equals {
  String message() default "同じ値ではありません";
 
  Class<?>[] groups() default {};
 
  Class<? extends Payload>[] payload() default {};
 
  String value();
 
  @Target({FIELD})
  @Retention(RUNTIME)
  @Documented
  public @interface List {
    Equals[] value();
  }
}

・Bean Validation実装

public class EqualsValidator implements ConstraintValidator<Equals, String> {
 
    private String target;

    @Override
    public void initialize(Equals equals) {
      target = equals.value();
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        UIComponent currentComponent = UIComponent.getCurrentComponent(FacesContext.getCurrentInstance());
        if (currentComponent != null) {
            //同階層にあるUIComponentを検索
            UIComponent component = currentComponent.getParent().findComponent(target);
            if (component != null && component instanceof UIInput) {
                UIInput uiInput = (UIInput) component;
                Object targetValue = uiInput.getSubmittedValue();
                //SubmittedValueがnullの場合は検証後のデータを取得
                if(targetValue == null) {
                    targetValue = uiInput.getValue();
                }
                //指定された項目と同じ値かをチェック
                if (value == null) {
                    return targetValue == null || targetValue.equals("");
                } else {
                    return value.equals(targetValue);
                }
            }
        }
        return true;
    }
 
}

・利用例(サーバ側)

public class TestData implements Serializable {
    private String val1;
    @Equals("val1")
    private String val2;

・利用例(画面)

<h:form id="form">
    <h:inputText id="val1" value="#{checkBean.testData.val1}" /><h:message for="val1" /><br />
    <h:inputText id="val2" value="#{checkBean.testData.val2}" /><h:message for="val2" /><br />
    <h:commandButton action="#{checkBean.check()}" value="送信" />
</h:form>

・実行結果
f:id:den2sn:20141221102913p:plain

val1とval2が同じでないとエラーになります。
なんとか作成できましたが、JSF依存の実装で、かつコンポーネントの配置やIDを意識する必要があるので微妙な作りとなってしまいました。JSFの正式対応が望まれます。*1

*1:Java EE 8で<f:validateWholeBean>タグが導入されました

GlassFish4.1リリース!

本日GlassFish4.1がリリースされました。
GlassFish Server Open Source Edition 4.1 Released! (The Aquarium)


同時にNetBeansの8.0.1もリリースされています。
もちろんGlassFish4.1がバンドルされています。
Welcome to NetBeans


GlassFish4.0はかなりバグを含んでいたので
これでかなり改善するんじゃないかと思います。

3ヶ月経ちました

日本オラクルに入社して3ヶ月が経ち、今月から無事正社員となりました。


やっと新しい環境にも慣れてきて、これからはさらに一歩踏み出した活動が出来ればなと思っていたりします。
直近はコンサルスキルの向上と1〜2年で達成する事を明確にするところからですね。


今は製品導入もやりつつJava EE導入のコンサル活動をやっています。
Java EEの導入で問題を抱えてる人がいれば気軽にお声がけ頂ければ相談に乗れると思います。

Java 8でJavaScript。スクリプトエンジンでNashornを試す

やや気が早いですが、Java 8のEarly Access版でお試し。
Nashornネタあまり出てこなそうなのでとりあえずスクリプトエンジンの復習です。


スクリプトエンジンはJava 6で導入された機能で、JavaVM上でJavaScriptRuby等のスクリプト言語が実行出来ます。特にJavaScriptJDKの中に実行エンジンが含まれているため、追加のライブラリ不要で使えるのがポイントです。Java 7でインボークダイナミックという機能が導入されJavaの中でスクリプトがより効率よく実行出来るようになりました。そして、Java 8でそのJavaScriptの実装がRhinoからインボークダイナミックを使ったNashornに置き換わります。つまり、よりJavaの中でJavaScriptが効率的に実行出来るようになるという事です。


では、とりあえずmainメソッドにソース書いてみます。

ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("js");
engine.eval("print(1+2);");


実行してみましょう。

3


わずか3行でJavaJavaScriptが動きますね。
うーんやっぱりJavaJavaScriptが動くのは不思議な感じ。
ちなみにengineのクラス名をSystem.outで出力してみると。

jdk.nashorn.api.scripting.NashornScriptEngine@6279cee3


確かにNashornになってます。


JavaからJavaScriptのfunctionを呼び出したい場合はScriptEngineクラスをInvocableにキャストすると呼び出せます。JavaScriptの「hoge」ファンクションをJavaから呼び出してみましょう。

engine.eval("function hoge(a,b){return a+b;}");
Invocable invocable = (Invocable) engine;
Object object = invocable.invokeFunction("hoge", 1, 2);
System.out.println(object); //3


キャストというのが少し微妙ですが、JavaからJavaScriptのfunctionが呼び出せて、JavaScriptからの戻り値もJavaで受け取る事ができます。


また、JavaScript内でJavaのクラスも扱えます。JavaScript内でLocalDateクラスを呼び出してみます。

engine.eval("print(Java.type('java.time.LocalDate').now());"); //2014-03-07


上記を実行すると今日の日付が出力されます。RhinoでimportPackage(またはimportClass)ファンクションを使用していましたが、Nashornは使用出来なくなっているので注意が必要です。どうしても互換性の為に使用する必要がある場合は、互換性スクリプトを事前に読み込む事で対応できます。

engine.eval("load('nashorn:mozilla_compat.js');importPackage(java.time);print(LocalDate.now());"); //2014-03-07


スクリプトエンジンはJavaの内部で簡易に記述出来るスクリプトが利用出来るほか、スクリプトで作成されたライブラリ資産がJavaで利用出来るようになるため、使い方によってはとても面白い事が出来ると思います。

Java 8の予習はお済みですか?

とうとう3/18のJava SE 8のリリースが近づいてきました。
去年あたりからJava界隈ではラムダ式などを中心としてJava SE 8の情報が出回っていますが、実際にはまだ触ってない人も多いのではないでしょうか。
少しでも慣れておく為にそろそろ準備運動でもしておいた方が良いかなと思います。
正式版ではありませんがEarly Access版がリリースされているので既にお試しで触ってみる事ができます。


JDK8 Early Access Releases
https://jdk8.java.net/download.html


IDEも対応は進んでいるようなのでリリース前にもかかわらず実際に試す環境は簡単に作れますね。地味にすごいことだと思います。


では、この辺り触っておいた方がいいよってところをあげてみます。


ラムダ式
まあ皆さん一番触ってみたいのがラムダ式でしょう。
型が省略出来る辺りがJavaとしてはやや違和感がありますね。
クロージャーじゃないので外の変数書き換え出来ないよとか、
thisの参照も内部クラスの挙動とは差異があるようなので実際試してみると面白いと思います。
ラムダ式とセットでメソッド参照やインターフェースのデフォルト実装なんかも入っているのでその辺りも要確認です。


・Date & Time API
Date & Time APIは今までのjava.util.Dateとはかなり違う上に今後の利用頻度はかなり高くなると思うので積極的に触ってみておいた方がいいですね。


・Nashorn
Java内のJavaScript実装エンジンがRhinoからNashornに変わります。まあどっちもサイですが。
実際速度差とかを試すのはあれですけど、Javaスクリプトエンジン試したこと無い人は一度試してみるのも良いと思います。


Java FX
GUI環境としてSwingの代わりにJavaFXが標準ライブラリとなりますね。JavaFXのハンズオン資料とかあるので、興味がある人はそれを参考に触ってみると良いと思います。JavaFXでは無名クラスを多く使うのでラムダ式とはとても相性が良いと思います。


Java 8で追加される機能は他にもありますがこの辺りをみればわかるのかな。
http://openjdk.java.net/projects/jdk8/features


Java EEは仕様がリリースされるので実際に本番利用出来るまでに時間がかかりますが、Java SEは実装がリリースされるので、
会社への適用速度もEEよりはスムーズに進むんじゃないかと思っています。


リリース待ち遠しいですね。