こんにちは、yanagitaです。
いつもPlay関連の話をしていますが、今回はAsta4dのscala対応についてお話します。
すでに本ブログでもasta4dの関する話はでていますが、元々Java向けのライブラリとなっているためScalaで使用とすると
Scalaの良さ活かせないところや仕様上使えないメソッドなんかがあったりします。
そのあたりを対応したAPIと回避策を紹介します。
過去のAsta4dに関する記事はコチラ
- JavaフレームワークAsta4Dの話 - astamuse Lab
- そうだAsta4dでWebアプリケーションを作ろう(第1回) - astamuse Lab
- そうだAsta4dでWebアプリケーションを作ろう(第2回) - astamuse Lab
- そうだAsta4dでWebアプリケーションを作ろう(第3回) - astamuse Lab
- そうだAsta4dでWebアプリケーションを作ろう(第4回) - astamuse Lab
- そうだAsta4dでWebアプリケーションを作ろう(第5回) - astamuse Lab
- そうだAsta4dでWebアプリケーションを作ろう(第6回) - astamuse Lab
事前準備
Scala向けのAPIの利用するにはasta4d-scalaライブラリを追加する必要があります。
以下、maven向け
<dependency> <groupId>com.astamuse</groupId> <artifactId>asta4d-scala</artifactId> <version>0.6</version> </dependency>
以下、sbt向け
libraryDependencies += "com.astamuse" % "asta4d-scala" % "0.6"
Renderer定義のScala対応
シンプル定義
asta4d-scalaライブラリを読み込むことでRendererの定義にArrowAssocが使用できるようになります。
以下、コーディングの比較
Java表記
public Renderer render() { Renderer render = Renderer.create(); render.add("#someIdForInt", 12345); render.add("#someIdForLong", 12345L); render.add("#someIdForBool", true); render.add("#someIdForStr", "a str"); render.add("#someIdForNull", (Object) null); render.add("#someIdForClear", Clear); Element newChild = ElementUtil.parseAsSingle("<div></div>"); render.add("#someIdForElementSetter", new ChildReplacer(newChild)); render.add("#someIdForElement", ElementUtil.parseAsSingle("<div>eee</div>")); render.add("#someIdForRenderer", Renderer.create("#value", "value")); return renderer; }
Scala表記
import com.astamuse.asta4d.scala.R._ def render(): Renderer = { "#someIdForInt" -> 12345 & "#someIdForLong" -> 12345L & "#someIdForBool" -> true & "#someIdForStr" -> "a str" & "#someIdForNull" -> (null.asInstanceOf[Object]) & "#someIdForClear"-> Clear & "#someIdForElementSetter" -> new ChildReplacer("<div></div>".parseAsSingle()) & "#someIdForElement" -> "<div>eee</div>".parseAsSingle() & "#someIdForRenderer" -> ("#value" -> "value") & "#someIdForRenderable" -> (()=>("#id" -> "xx").asRenderer()) }
ArrowAssoc定義のお陰でシンプルで読みやすくなり、scalaで書く方にとっては単純にコーディングできるようになったかと思います。
少し解説します。
scala側でArrowAssocを使ったコーディングを行うために「com.astamuse.asta4d.scala.R._」をインポートします。
続けて、定義はTuple2の第一引数にセレクタ、第二引数に挿入する値を設定します。これが1つのRenderer定義になります。
// 結果は一緒 render.add(セレクタ, 挿入する値); // Java セレクタ -> 挿入する値 // Scala
複数Rendererを定義する場合は「&」でTuple2を繋いでいきます。
これはインポートしたR配下のメソッドがArrowAssocで定義されたTuple2を暗黙的にRendererオブジェクトに変換し、「&」でRenderer#addメソッドに変換する仕組みとなっています。
暗黙部分を取り除くと下のイメージとなります。
Scala表記
"#someIdForInt" -> 12345 & "#someIdForLong" -> 12345L & "#someIdForBool" -> true &
Java表記
Renderer.create("#someIdForInt", 12345) .add(Renderer.create("#someIdForLong", 12345L)) .add(Renderer.create("#someIdForBool", true))
では、次は上記以外のRenderer定義について紹介します。
配列定義
Java表記
public Renderer render() { return Renderer.create("#someIdForRenderer", Arrays.asList(123, 456, 789), new RowRenderer<Integer>() { @Override public Renderer convert(int rowIndex, Integer obj) { return Renderer.create("#id", "id-" + obj).add("#otherId", "otherId-" + obj); } }); }
Scala表記
import com.astamuse.asta4d.scala.R._ def render() = { "#someIdForRenderer" -> List(123, 456, 789).map { i => { "#id"-> ("id-" + i) & "#otherId"-> ("otherId-" + i) }} }
配列を使用した場合はJava側で定義していたRowRendererが不要となり、mapメソッドのみで記述できるようになります。
属性定義
Java表記
public Renderer render() { Renderer render = Renderer.create(); render.add("#id", "+class", "yyy"); render.add(("#id", "-class") -> "zzz"); render.add("#id", "+class", "xxx"); render.add("#id", "value", new Date(123456L)); render.add("#id", "href", null); render.add("#idstr", "value", "hg"); render.add("#idint", "value", 3); render.add("#idlong", "value", 3L); render.add("#idbool", "value", true); return render }
Scala表記
import com.astamuse.asta4d.scala.R._ def render() = { ("#id", "+class") -> "yyy" & ("#id", "-class") -> "zzz" & "#id" -> "+class" -> "xxx" & "#id" -> "value" -> new Date(123456L) & "#id" -> "href" -> null & "#idstr" -> "value" -> "hg" & "#idint" -> "value" -> 3 & "#idlong" -> "value" -> 3L & "#idbool" -> "value" -> true }
ArrowAssoc定義で属性を指定する場合は、セレクタ、属性指定、挿入する値を一括りで定義します。
(セレクタ -> 属性指定) -> 挿入する値 or セレクタ -> 属性指定 -> 挿入する値
いかがだったでしょうか?
asta4d-scalaでscalaライクなコーディングができるようになったと思います。
メソッド名と予約語のバッティング対応
URLルールの定義でパラメータを設定する役割としてvarメソッドが存在しますが、
この「var」scalaでは予約語となっておりメソッド名や変数名に使用することができません。
回避方法としては2つ、
1つ目がメソッド名をアクサングラーブでかこ囲って使用する。
2つ目がvarメソッドと同じ処理を持つpathVarメソッドを使用する。
これでメソッド名のバッティングを回避できます。
// ↓ コンパイルエラー varが予約後 rules.add("/app/{name}/{age}", "/templates/variableinjection.html") .var("extraVar", 1234); // ↓ アクサン グラーブで囲ってコンパイルエラーを回避 rules.add("/app/{name}/{age}", "/templates/variableinjection.html") .`var`("extraVar", 1234); // ↓ pathVarメソッドでコンパイルエラーを回避 rules.add("/app/{name}/{age}", "/templates/variableinjection.html") .pathVar("extraVar", 1234);
個人的には後者を使って頂くのが違和感がない実装になるかと思います。
以上、JavaライブラリAsta4dをscalaで使用するための紹介でした。
今後Scala対応が進んでいく中で興味を持って頂ける方が少しでも増えることを願っています。
更新があればまたこちらでご紹介します。
■ asta4d-scala github.com
弊社まだまだエンジニア&デザイナーを絶賛募集中です。
・Webデザイナー
・Webアプリケーションエンジニア(Java)
・Webアプリケーションエンジニア(Scala)
・データ開発エンジニア
採用に関するQAコチラ lab.astamuse.co.jp