読者です 読者をやめる 読者になる 読者になる

Java EE 事始め!

主にJava EEについて、つらつらとマイペースに書いていきます。「Java EEを勉強するときに、一番最初に読んでもらえるブログ」を目指して頑張ります!

Spring Boot 1.4でThymeleaf 3を使う

Spring Boot Thymeleaf Spring Framework

プロジェクト作成は、Spring Initializrとかで作成済みの前提です。

Spring Boot 1.4では、デフォルトでThymeleaf 2が使われます。

Thymeleaf 2ではXHTMLで書く必要がありますが、Thymeleaf 3だと完全にピュアなHTMLで書くことが可能です。

pom.xmlのpropertiesに下記の記述を追加します。

    <properties>
        <!-- その他のプロパティは省略 -->
        <thymeleaf.version>3.0.1.RELEASE</thymeleaf.version>
        <thymeleaf-layout-dialect.version>2.0.1</thymeleaf-layout-dialect.version>
    </properties>

Thymeleaf 3のバージョンと共に、Thymeleaf Layout Dialectのバージョンも指定する必要があります。

これだけで完了で、あとはビルドしなおせばThymeleaf 3が使われます。

Bean定義なども記述する必要はなく、本当にこれだけでおしまいです。

Gradleの場合はこちらを参照してください。

Support Thymeleaf 3 · Issue #4393 · spring-projects/spring-boot · GitHub

Java EE 7を勉強する方法(2016年ver.)

Java EE 7

今年になって、Java EEの学習環境がガラッと変わりました。

2016年も半分以上過ぎてしましましたが(笑)、今からJava EE 7を勉強するにはどうすべきか、改めて書きたいと思います。

1. まずは作りながら学ぶ

以下3冊のいずれか1つで、Webアプリを作りながらJava EEの概要を理解しましょう。本屋さんで軽く立ち読みして、ご自分に合いそうな本を1つ選んでください。

www.shuwasystem.co.jp

www.shuwasystem.co.jp

www.shoeisha.co.jp

これらの本は、いずれもWebアプリを作りながらJava EEの基本を学ぶ、チュートリアルのような形式です。

「わかりやすいJava EE」と「パーフェクトマスター」は、サーブレットJSPの学習が終わったJava初心者の方向けです。ただし、RESTful Webサービスを作る技術「JAX-RS」の説明は、2冊とも無いので注意してください。

ある程度のJavaの経験(Webフレームワーク、DIコンテナ、ORマッパーを使った開発経験)があるならば、「Java EE 7徹底入門」が良いでしょう。この本には、JAX-RSの章があります。

2. ブログ情報を調べてみる

上記の入門書籍だけでは、実開発には足りない部分があると思います。

多くの方がブログやスライドを書かれていますので、ぜひ参考にしてみてください。

JSF

JSFでは、まずは菊田さん(@kikutaro_)のブログを読んでいただくのが良いでしょう。

JSF カテゴリーの記事一覧 - Challenge Java EE !

その他の読んでおくべき情報は、下記の記事にリンクをまとめておきました。

JSFを使うなら読んでおきたいリンクまとめ - Java EE 事始め!

JAX-RS

JAX-RSでは、まずはうらがみさん(@backpaper0)のスライドを読みましょう。

JAX-RS入門および実践

ブログはこちら。

この投稿のタグ JAX-RS — 裏紙

アクションベースMVC

Java EEの情報を調べていると、「JSFコンポーネントベースで、Strutsはアクションベースで・・・」という情報が見つかることも多いと思います。

アクションベースMVCは、現在はまだJava EE 7標準ではありませんが、使うこと自体は可能です。僕のスライドを読んでいただくのが一番良いと思います。

Java EEアクションベースMVC入門 #jjug_ccc #ccc_cd4 // Speaker Deck

CDI

上妻さん(@n_agetsu)のブログが良いでしょう。リンクは下記にまとめています。

CDI/JTAを使うなら読んでおきたいリンクまとめ - Java EE 事始め!

JPA

まずは、拙著スライドからどうぞ。

はまる!JPA(初学者向けライト版)
http://www.slideshare.net/masatoshitada7/jpa-46874399

より高度な内容については、下記のスライドを読んでみてください。

はまる!JPA
http://www.slideshare.net/makingx/jpa-29150059

金魚本に載ってないJPQLの話
http://d.hatena.ne.jp/megascus/20120925/1348575449

アプリケーションサーバ

サーバーそれぞれのエキスパートの方々がブログを書かれています。

GlassFish Japan

nekop's blog

yamadamnのはてな日記

Java EE全般

  • Java EE 7 Tutorial日本語訳まとめ

Java EE 7 Tutorialは、Oracle公式のチュートリアルです。全部ではありませんが、@kagamihogeさんが日本語訳をまとめていらっしゃいます。

The Java EE 7 Tutorialのテキトー翻訳まとめ - Qiita

  • ○○使い方メモ

@opengl_8080さんのブログです。Java EEに限らず、いろんな情報が書かれていてとても素晴らしいです。

特に、Bean ValidationとJTAの記事は必読です。

JavaEE使い方メモ(Bean Validation) - Qiita

JavaEE使い方メモ(JTA) - Qiita

各種Advent Calender

Java EE Advent Calendar 2015 - Qiita

Java EE Advent Calendar 2014 - Qiita

GlassFish Advent Calendar 2014 - Adventar

GlassFish Advent Calendar 2013 - Adventar

JBoss / WildFly (全部俺) Advent Calendar 2013 - Adventar

3. 仕上げは「パーフェクトJava EE」!

Java EE 7日本語書籍の決定版とも言うべき本です。内容の質・量とも素晴らしいです。開発でJava EEを使う方は必読でしょう。

gihyo.jp

4. 公式情報も確認しよう

かなり日本語情報が充実してきましたが、できれば英語の公式情報にも目を通しておきましょう。日本語情報が無い場合には、英語の1次情報をあたるのが最も良い方法です。OracleJava EE 7公式情報は、こちらにまとめられています。
Home: Java Platform, Enterprise Edition (Java EE) 7 Release 7

また、仕様書であるJSRも重要です。JSRはこちらから検索できます。「JPA JSR」のように「技術名 JSR」でググってもOKです。
The Java Community Process(SM) Program

まとめ

  • まずは書籍を読んで、手を動かしながらJava EEの基本を身につける!
  • 重要なブログ情報をチェック!
  • パーフェクトJava EEで仕上げ!
  • 公式情報もしっかりチェック!

もはや「Java EEは日本語情報が少ない」とは言えません。日本語情報は、現存の技術の中ではかなり充実している方だと思います。

ただし、日本語情報はGlassFish前提で書かれているものが多く、その他のサーバーでは細かい挙動が異なることも多々あります。

トラブル時に大事になってくるのは、英語の公式情報です。英語情報もしっかりとチェックしましょう。

それでは、Enjoy Java EE

【書評】「パーフェクトJava EE」は最強のJava EE 7リファレンス!

https://www.amazon.co.jp/パーフェクト-Java-EE-井上-誠一郎/dp/4774183164www.amazon.co.jpgihyo.jp

著者の1人である@kikutaro_さんから献本いただきました。ありがとうございます!

これまでのJava EE書籍の課題

まずは、Java EEの最新バージョンである「Java EE 7」対応の日本語書籍が少ないことでした。

なので、下記のEE 5本やEE 6本で勉強した後は、ブログ情報を検索したり、海外の英語情報に頼るしかありませんでした。

https://www.amazon.co.jp/マスタリングJavaEE5-第2版-DVD付-Programmer’s-SELECTION/dp/4798120545

https://www.amazon.co.jp/Beginning-6%7EGlassFish-3で始めるエンタープライズJava-Programmers-SELECTION/dp/4798124605

2014年暮れあたりから、徐々にEE 7対応の書籍も出始めました(下記)。

www.shuwasystem.co.jp

www.shuwasystem.co.jp

www.shoeisha.co.jp

これらはそれぞれ非常に良い本なのですが、3冊ともチュートリアル形式で、1つのアプリケーションを作っていく中でJava EEの機能を学習していくというスタイルの本です。

なので、初期学習には非常に良いのですが、「困った時に頼りになるリファレンス」というような本ではありません。リファレンスとなるような本は「マスタリングJava EE 5」しか無い、というのが現状でした。

待望の「Java EE 7で困った時に頼りになるリファレンス」が登場!

今回登場した「パーフェクトJava EE」は、待望の「リファレンスとして使える本」です。

内容はJSFJAX-RSCDIJPAが中心です(WebSocket・Bean Validation・JTAEJBも1章ずつ解説があります)。つまりJava EEのWebプロファイルですね。

それぞれがその技術のエキスパートによって書かれています(JSFは菊田さん、JAX-RSは井上さん、CDIは上妻さん、JPAは槙さん)。この技術だったらこの方だろう、という人ばかりですね。

内容の幅も深さも、他の書籍とは一線を画しています。

例えばWebSocketの章では、エンコーダーデコーダーを利用してJSON形式でデータをやり取りする方法が紹介されています(WebSocketってチャットアプリ作っておしまい、みたいな解説が多いですよね...)。

その他、CDIのクライアントプロキシ、JAX-RSのMessageBodyReader/Writerの性質、JSFのPrimeFaces、JPAのエンティティグラフやL2キャッシュなど。

その他にも重要な内容がたくさん書かれていますので、ぜひ読んでみてください。Java EEを開発で使っているすべての方必見の内容が詰まっています!

かなり高度な内容も書かれていますので、基礎知識なしで読むのはハードルが高いかもしれません。なので、上記3冊のチュートリアル形式の本をどれでもいいので読了してから、パーフェクトJava EEを読むことをお勧めします。

ちょっと気になった点

FacesContextのインジェクト(P.36)

@Inject
FacesContext facesContext;

このように書けるようになるのは、確かJava EE 8からだったと記憶しています。

Payara Web ML 4.1.1.162で上記のコードを試しましたが、デプロイ時にエラーになりました。

セッションIDの変更(P.352)

セッションIDを変更するためにHttpSessionの破棄および再生成を行っていますが、下記のようにHttpServletRequest#changeSessionId()メソッドを利用すれば、再生成の必要は無いと思います。

HttpServletRequest request = 
    (HttpServletRequest) FacesContext.getCurrentInstance()
        .getExternalContext().getRequest();
request.changeSessionId();

レルムの説明が少ない

レルムでの認証・認可は、サーブレットの章でサラッと数ページで説明されているだけでした。

レルムはあんまり使わないよ、というメッセージなのでしょうか?深読みし過ぎ?

最後に

著者の井上さん・槙さん・上妻さん・菊田さんには、本当に感謝の言葉しかありません。

これだけの質と量の書籍を書くという作業は、本当に大変だったと思います。

とても貴重な書籍を書いていただき、ありがとうございました!

Thymeleafのビューから@NamedなCDI管理ビーンにアクセスする

やりたいこと

こんなCDI管理ビーンがあって、

@Named
@SessionScoped
public class SessionDto implements Serializable {

    private String id;

    public String getId() {
        return id;
    }
}

Thymeleafのビューからこんな感じで参照したいです。

<p th:text="${sessionDto.id}">...</p>

本当は上記みたいにやりたかったのですが、現時点では、下記のような感じで参照することができました。

<p th:text="${#cdi.bean('sessionDto').id}">...</p>

以下、やり方を解説します。

名前からCDI管理ビーンを取得するクラスの作成

package com.example.rest.thymeleaf;

import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.CDI;
import java.util.Set;

public class Cdi {

    public Object bean(String name) {
        CDI<Object> cdi = CDI.current();
        BeanManager beanManager = cdi.getBeanManager();
        Set<Bean<?>> beans = beanManager.getBeans(name);
        Bean<?> bean = beanManager.resolve(beans);
        Class<?> beanClass = bean.getBeanClass();
        return cdi.select(beanClass).get();
    }
}

引数のnameをもとに、ビーンを取得するメソッドを作ります。

まずBeanManagerを取得して、名前からSet<Bean<?>>を取得します。

名前だけではビーンを1つに特定できない(セッションスコープとかだとユーザー数だけ同じ名前のビーンがあるため)ので、resolve()でビーンを1つに特定します。

そこからビーンのClassオブジェクトを取得し、cdi.select(beanClass).get()でようやっと目的のCDI管理ビーンそのもののインスタンスを取得できます。

何か効率的ではないような感じがするので、今後変更するかもしれません。

参考資料

羽生田さんのスライド 3.Java EE7 徹底入門 CDI&EJB

かずひらさんのブログ CDIのBeanManagerを使う - CLOVER

CDI管理ビーンを参照するDialectを自作する

ThymeleafのDialectを自作します。

まず、IExpressionObjectFactory実装クラスを作成します。

この中で、先ほど作成したCdiクラスをnewしています。 ビューからは、getAllExpressionObjectNames()で返している名前でアクセスできます。

package com.example.rest.thymeleaf;

import org.thymeleaf.context.IExpressionContext;
import org.thymeleaf.expression.IExpressionObjectFactory;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

public class CdiExpressionFactory implements IExpressionObjectFactory {

    private static final String EXPRESSION_OBJECT_NAME = "cdi";

    private static final Set<String> ALL_EXPRESSION_OBJECT_NAMES =
            Collections.unmodifiableSet(new HashSet<>(Arrays.asList(EXPRESSION_OBJECT_NAME)));

    @Override
    public Set<String> getAllExpressionObjectNames() {
        return ALL_EXPRESSION_OBJECT_NAMES;
    }

    @Override
    public Object buildObject(IExpressionContext context, String expressionObjectName) {
        if (EXPRESSION_OBJECT_NAME.equals(expressionObjectName)) {
            return new Cdi();
        }
        return null;
    }

    @Override
    public boolean isCacheable(String expressionObjectName) {
        return false;
    }
}

次に、Dialectクラスを作成します。

IDialectというインタフェースがあり、そのサブインタフェースとして下記の5つがあります。

  • IProcessorDialect
  • IPreProcessorDialect
  • IPostProcessorDialect
  • IExpressionObjectDialect
  • IExecutionAttributeDialect

今回は、IExpressionObjectDialectを使いました。他の4つはまだ試せていません...(^^;

package com.example.rest.thymeleaf;

import org.thymeleaf.dialect.AbstractDialect;
import org.thymeleaf.dialect.IExpressionObjectDialect;
import org.thymeleaf.expression.IExpressionObjectFactory;

public class CdiDialect extends AbstractDialect implements IExpressionObjectDialect {

    private static final IExpressionObjectFactory EXPRESSION_OBJECT_FACTORY = new CdiExpressionFactory();

    public CdiDialect() {
        super("cdi");
    }

    @Override
    public IExpressionObjectFactory getExpressionObjectFactory() {
        return EXPRESSION_OBJECT_FACTORY;
    }
}

参考資料

Thymeleafのドキュメント Tutorial: Extending Thymeleaf

Thymeleafのソースコード

自作Dialectの追加

TemplateEngineをnewしている場所で、自作Dialectを追加します。

templateEngine = new TemplateEngine();
templateEngine.addDialect(new CdiDialect());

ビューの作成

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
      ...
<p th:text="${#cdi.bean('sessionDto').id}">...</p>

#cdi.bean()で自作したCdiクラスのbean()メソッドを呼び出しています。

引数には@Namedで指定したビーン名を指定します。

今回は@Namedvalue属性をしていていないので、「クラス名の頭文字を小文字にした名前」がビーン名になります。

まとめ

今回の方法は「Expression Object」(#で始まるやつ)を使ってみました。

この方法は非常に簡単でいいですね。他の方法も試してみたいです。

コードはこちら。

https://github.com/MasatoshiTada/jjug-action-based-mvc/tree/master/jjug-my-mvc

ThymeleafでJava SE 8のDate and Time APIを使う方法

やりたいこと

Thymeleafのビューで、java.time.LocalDateなどJava SE 8で入った日時クラス(Date and Time API)を使いたい。

Date and Time APIについてはこちらをどうぞ。

Java日付時刻APIメモ(Hishidama's Java8 Date and Time API Memo)

(蓮沼さんの資料は何故か見つからなかった・・・)

Thymeleafの拡張機能を追加

Thymeleafには、Date and Time APIを利用するための拡張機能があります。

https://github.com/thymeleaf/thymeleaf-extras-java8time

本体に入っていないのは恐らく、Thymeleaf本体はJava SE 6でコンパイルされているからだと思われます。

thymeleaf/CONTRIBUTING.markdown at 3.0-master · thymeleaf/thymeleaf · GitHub

pom.xmlに依存性を追加します。

<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-java8time</artifactId>
    <version>3.0.0.RELEASE</version>
    <scope>compile</scope>
</dependency>

Dialectの追加

TemplateEngineをnewしている場所で、Java8TimeDialectを追加します。

templateEngine = new TemplateEngine();
templateEngine.addDialect(new Java8TimeDialect());

ビューからの利用

こんなクラスがあって、

public class Employee {
    ...
    private java.time.LocalDate joinedDate;
    // getter/setter
}

ThymeleafでjoinedDateをフォーマットして表示するには、下記のようにします。

<tr th:object="${employee}">
    ...
    <td th:text="*{#temporals.format(joinedDate, 'yyyy-MM-dd')}">2020-01-01</td>

簡単ですね!

その他の機能

こちらのREADMEに、一通りの機能が説明されています。

https://github.com/thymeleaf/thymeleaf-extras-java8time

JJUG CCC 2016 SpringでアクションベースMVCの発表してきた&楽しんできた #jjug_ccc

発表してきた

「ネクストStruts/Seasar2としてのJava EEアクションベースMVC入門」というタイトルで発表してきました。

165人の部屋が、ほぼ満席となるくらいの方々にお越しいただきました。ありがとうございます。

やっぱり、StrutsSeasar2からの移行をどうするかは、皆さん喫緊の課題だと思います。

内容はJava EE 8のMVC 1.0、そしてEE 7における代替としてJersey MVCとRESTEasy HTMLです。

ビューは頑張ってThymeleafをリリースされたばかりの「3」にしたり、

クライアント側のロケールに合わせて画面のメッセージや検証エラーメッセージを国際化したりしました。

MVC 1.0のサンプルのみ、検証エラーメッセージの国際化には対応していません。現在、MVC 1.0の仕様策定で検討中のためです。

資料

コード

GitHub - MasatoshiTada/jjug-action-based-mvc: JJUG CCC 2016 Spring「ネクストStruts/Searar2としてのJava EEアクションベースMVC入門」のサンプル

楽しんできた

テスト自動化のまわりみち(@irofさん)

テスト自動化などの前に、テスト技法なりテスト項目書の書き方なり、基本的なことをきちんとやりましょう、ということだと理解しました。

例えば、「◯◯が正しいこと」ではなく「◯◯の値が『10』になっていること」と書くとか。

「正しいこと」なんて、そりゃJUnitで表現できませんよね・・・。

テスト技法の研修などもやったりする身としては、身が引き締まる思いでした。

Thymeleaf 3を使ってみよう!(@bufferingsさん)

Thymeleaf公式ドキュメントの和訳も出されている椎葉さんのセッションでした。

アクションベースMVCのサンプルを作る時に一通りドキュメントを読んだので、概ね知っている内容が多かったのですが、

初めて知ったことや、いまひとつ理解できていなかったことが理解できたことも多かったです。

さらに、椎葉さんは実業務でもThymeleafを使っていらっしゃるということで、デザイナーさんとの協業の話も非常に参考になりました。

Spring BootでBootした後に作るWebアプリケーション基盤(エムスリー吉田さん)

Spring Boot + Spring MVCの実用的な使い方のお話でした。

特に例外処理やロギングなどのお話が印象的でした。スライドはアップされないのかな?

Spring Framework/Bootの最新情報とPivotalが進めるクラウドネイティブなアプローチ(@makingさん)

最初に、Spring Boot 1.4およびSpring Framework 4.3の新機能のお話でした。

テスト関連の機能が特に印象的でした。テストしやすいフレームワークっていいよなあ・・・。Java EEにも頑張ってほしい。

後半は、Cloud FoundryやConcourse CIなどの紹介をしつつ、「クラウドネイティブ」なアプリケーションとは何か、

それをCloud Foundryではどう実現しているか、というお話でした。

以前にCloud Foundryワークショップにも参加したので、もっと触れていきたいなあと思います。

Seasar2で作った俺たちのサービスの今(@jukutyoさん)

Seasar2(Cubby + S2Dao)からSpring MVC + Domaへ移行するお話でした。

段階的に移行していて、今は同一WARファイルの中にSpringとSeasar2が同居している状態だそうです。

確かに、一度にまるっと移行することは、人的・時間的リソースや、サービスを維持・発展させなければならない、

といった制約もあって現実的でないこともあると思いますので、こういった実例を知れたのは非常に良かったです。

余談ですが、じゅくちょーさんは元塾講師ということで、塾講師っぽい喋り方が印象的でした。

僕も学生時代は塾講師のバイトをずっとしていたので、なんだか懐かしい気持ちでしたw

マイクロフレームワークenkan(とkotowari)ではじめるREPL駆動開発(@kawasimaさん)

システムエンジニアアドベントカレンダーで世の中を驚かせた、川島さんの発表でした。

川島さんとしては色々な問題意識をお持ちで、このenkanを作るに至ったそうです。

確かに、XMLアノテーションになっても、設定が面倒なのはあるし、CoCと分かりやすさはトレードオフです。

最後の方はチュートリアルをやってみる時間がありましたので、やってみました。

最初にMavenでのJARのダウンロード祭りがありますが、それでも5分くらいあれば、このチュートリアルは終えられました。

運営について

今回から昼休みが90分になったり、午後にも2セッションごとに40分の休憩があったり、

懇親会の開始時間が早まったり、新たな取り組みがありました。

特に午後の長めの休憩は、非常に嬉しかったです。

10分休憩だけで午後に6セッションとか7セッションとか続くと、かなり体力的にキツかったですし、

休憩時間が短いとセッション間の移動も混雑して大変でした。

所々に長めの休憩があることで、体力も回復できるし、余裕を持って移動できるし、

いろんな方とお話しすることもできるし、個人的にはいいことずくめでした。

幹事やボランティアスタッフの皆様、ありがとうございました!

おまけ

このタイムテーブル、とても役に立ちました!

@YujiSoftwareさん、ありがとうございます!

http://yujisoftware.github.io/jjug-ccc/2016-Spring/

EclipseLinkとHibernateではTemporalType.DATEなフィールドの型が違う

Java EE 7 GlassFish Payara JPA WildFly

かなり久々のJPAネタ。

こんなエンティティクラスがあって、

@Entity
public class Employee implements Serializable {
    @Id
    @Column(name = "emp_id")
    private Integer empId;
    
    @Temporal(TemporalType.DATE)
    @Column(name = "joined_date")
    private java.util.Date joinedDate;
    

joinedDateというフィールドはjava.util.Date型、そして@Temporal(TemporalType.DATE)が付いています。

これをEclipseLinkで実行すると、joinedDateにはjava.util.Date型のインスタンスが代入される。

一方、Hibernateで実行すると、joinedDateにはjava.sql.Date型のインスタンスが代入される。(java.sql.Datejava.util.Dateのサブクラスです)

Webアプリのビューでそのまま表示すると、Payara(JPA実装がEclipseLink内包)だと「Wed Apr 01 00:00:00 JST 2015」という形式なのに、

WildFly(JPA実装がHibernate)だと「2015-04-01」という形式になったので、アレ?と思って、

employee.getJoinedDate().getClass().getName()してクラス名を表示したらこんな感じになってました。

jug-action-based-mvcプロジェクトにテストコードを追加しました。

EmployeeDaoのテストコードを追加 · MasatoshiTada/jjug-action-based-mvc@2edd12b · GitHub