JavaEE 8/MVC 1.0 RI Ozark + Handlebarsを試す

久々にだれでも気軽に使えそうなJavaEEのパーツが出てきたようなので、自分で動かしてみる。

まずJAX-RSを動かす

とりあえずMVC1.0のセットアップなどは以下を参照。
http://masatoshitada.hatenadiary.jp/entry/2015/03/31/220509


まずはベースとなるJAX-RS部分がちゃんと動くか動作確認する。

package com.shingames.mvc1.ozarchbs;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("hellojaxrs")
public class HelloJaxrs {
    
    //通常のJAX-RS
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String jaxrs(){
        return "hello JAX-RS";
    }
}

これくらいが動けばよい。

Handlebarsを動かす

JSPもFreeMakerもVelocityもよくあるテンプレートでやっても面白くないのでHandlebarsを使う。

エクステンションがすでに用意されているので以下のように依存性部分に追加する。
https://shinsan.s3.amazonaws.com/diary/2015/0412-01.png
NetBeansだとプロジェクトツリーで依存性を右クリック、依存性を追加でこのダイアログを出せる。


リソースクラスを以下のように記述する。

package com.shingames.mvc1.ozarchbs;

import com.oracle.ozark.core.Models;
import com.oracle.ozark.ext.handlebars.HandlebarsViewEngine;
import javax.mvc.Controller;
import javax.mvc.Viewable;
import javax.ws.rs.GET;
import javax.ws.rs.Path;

@Path("hellomvc")
public class HelloMvc {
    
    
    //MVC1.0 Controllerのアノテーションがあるだけ
    @Controller
    @GET
    public Viewable mvc(){
        Models models = new Models();
        models.put("message", "<b>MVC 1.0</b>");
        models.put("loop", new String[]{"1","2","3","4"});
        return new Viewable("hello.html", models, HandlebarsViewEngine.class);
    }
}

大体何を書いているかわかると思うが、ここで利用しているModelsはjavax.mvcパッケージのModelsではなくてozarkなのに注意する。javax.mvcのModelsはMAPインターフェースのみで実装がないため。またCDIのリクエストスコープが付いていて少しややこしいが、今回は無視で。

Viewableの引数が多いが、これはテンプレートエンジンを強制でHandlebarsを利用したいため。デフォルトでは拡張子をもとに判定するのと、拡張子をかえるとツールのサポートが失われるため変更したくないのでこうしてある。

テンプレートが固定の場合@Viewでテンプレート名を設定できるのだが、これはエンジン指定はできないため使えない。
この辺の柔軟性は正式版までには改善するだろうか。


テンプレートはWEB-INF直下にviewsディレクトリを作成してそこに突っ込む。

<!DOCTYPE html>

<html>
    <head>
        <title>MVC 1.0</title>
        <meta charset="UTF-8">
    </head>
    <body>
        <div>Hello {{message}}!</div>
        <div>Hello {{{message}}}!</div>
        {{#loop}}
            <div>{{this}}</div>
        {{/loop}}
    </body>
</html>

JAX-RSNetBeans上では右クリックでブラウザ起動できるのでGETだけならこれで手軽に試せる。
https://shinsan.s3.amazonaws.com/diary/2015/0412-02.png

実行結果
https://shinsan.s3.amazonaws.com/diary/2015/0412-03.png
想定通り。

ModelsがCDIであることを確認する

リソースクラス。

package com.shingames.mvc1.ozarchbs;

import com.oracle.ozark.ext.handlebars.HandlebarsViewEngine;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.mvc.Controller;
import javax.mvc.Viewable;
import javax.ws.rs.GET;
import javax.ws.rs.Path;

@Path("hellologic")
@RequestScoped
public class HelloLogic {
    @Inject
    Logic logic;
    
    @Controller
    @GET
    public Viewable logic(){
        logic.run();
        return new Viewable("hello.html",  HandlebarsViewEngine.class);
    }
}

ロジック

package com.shingames.mvc1.ozarchbs;

import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;

@RequestScoped
public class Logic {
    @Inject
    com.oracle.ozark.core.Models models;
    
    public void run(){
        
        models.put("message", "<b>MVC 1.0</b>");
        models.put("loop", new String[]{"A","B","C","D"});
    }
}

実行結果
https://shinsan.s3.amazonaws.com/diary/2015/0412-04.png

リソースクラスからはテンプレートに渡すModelsすら消えた。
Viewableの引数からも消えている。
このようにJAX-RS側は単純にパラメータやURLなどのマッピングやロジックの呼び出しのみ記述するというやり方もいいだろう。CDI経由で必要なリクエスト情報などが取得できる。

今回はわかりやすくなるように書いたがModelsが実装依存なのかそうでないのかパッケージは意識すること。

現状

まだアーリードラフトレビュー用ということで、たたき台程度のものでしかない。

そもそもJerseyMVC使っている人にとって新しさはどこにもないため面白くもない。ただ、標準化されることでやっとStruts1を捨てる圧力が強くなるといったところか。

MVCといいつつもJAX-RSにおけるVのみのプラグイン的なもの、それも自前でBodyWriter等かけばできる程度のものであるため本当に面白くはない。

テンプレートといえばスタンドアロンで動かしやすそうだが、CDIサーブレットAPIに依存した実装のため、このままではスタンドアロンでは動かせない。

とはいえ、開発者はサーブレットAPIはさわらないし、ロジックは切り離ししやすいし単体テストはしやすいとは思う。


個人的にはCDI依存、サーブレットAPI依存部分をなくしてもらうのは大前提として、さらにできればどのJAX-RS実装の上でも動くようにしてもらいたいところではある。