去年、こんなエントリを書きました。
Apache Velocity 2.0がリリースされたよという話 - CLOVER🍀
去年の8月にApache Velocity(正確にはApache Velocity Engine)の2.0がリリースされた、という話でした。
ただ、その時はApache Veloticy Toolsはまだリリースされていませんでした。
それが、ようやく最近になってリリースされました。リリース日は、2018年10月9日。
http://velocity.apache.org/tools/3.0/
リリースノートは、こちら。
Velocity Tools 3.0 Release Notes
今回も、せっかくなのでちょっと見ていきたいと思います。
お断り
去年のエントリの時にも書いたのですが、同じようなことをまた書きます。
世間的には、Apache Velocityはすでに役目を終えた印象のテンプレートエンジンかと思います。Spring Frameworkからの
サポート対象外、Apache Velocity (Engine) 2.0がリリースされてから、Viewなどで使うのに必要となるApache Velocity Toolsは
未リリースという状態でしたが、それがリリースされるまで1年かかっていますしね。
そんなわけで去年のエントリからの繰り返しになりますが、ここから先は、それでもApache Velocityに興味のある方だけ
ご覧になればよろしいかなと思います。
Apache Velocity Tools 3.0
Apache Velocity Tools 3.0での変更内容や
http://velocity.apache.org/tools/3.0/
Velocity Tools 3.0 Release Notes
アップグレードガイドは、こちら。
ざっくりまとめると
- Velocity Engine 2.0に依存してるよ
- CollectionToolとJsonToolが増えたよ
- BrowserTool、ImportTool、XmlToolは書き直されたよ
- groupIdは「org.apache.velocity.tools」になったよ
- LinkToolは現在のリクエストパラメーターのコピーを作成するのが簡単になったよ
- "input.encoding"をちゃんと使うようになったよ
- JSPタグライブラリが使えるようになったよ
- DateToolのローカライゼーションの改善
- SortToolで任意のComparatorが指定できるようになったよ
- テンプレートでログ出力する、LogToolを追加したよ
- JsonToolは、GenericとView用の2つがあり、View用の方はHTTP POSTで送信されたJSONをパースできるよ
といったところです。
依存するApache Velocity Engineが2.0になったことにより、ログはSLF4Jを使って出力されるようになりました。
また、アーティファクトも分割され、
- velocity-tools-generic
- velocity-tools-view
- velocity-tools-view-jsp
https://search.maven.org/search?q=g:org.apache.velocity.tools
となりました。viewが付く方はWeb用で、Servlet APIに依存しています。view-jspとなると、JSPにも依存します。
Apache Velocity Tools 2.0の頃は、まるっとひとつのアーティファクトでした。
サンプルなどは、こちらを見ると良いでしょう。
Apache Velocity Tools - Standalone Tools
なんですが、なにか劇的に変わった感じはしませんね…。
JsonToolを試してみる
とはいえ、本当になにもしないのもなんなので、ここはひとつ、新しいVelocityToolでも試してみましょう。
ここでは、JsonTool(Genericの方)を試してみることにします(CollectionToolは文字列のsplitと、Collectionのソートが
できるくらいみたいなので)。
利用するMaven依存関係は、こちら。
<dependency> <groupId>org.apache.velocity.tools</groupId> <artifactId>velocity-tools-generic</artifactId> <version>3.0</version> </dependency>
こんな感じのサンプルプログラムを用意。
src/main/java/org/littlewings/velocity/VelocityToolsExample.java
package org.littlewings.velocity; import java.io.StringWriter; import java.util.Properties; import org.apache.velocity.app.Velocity; import org.apache.velocity.context.Context; import org.apache.velocity.tools.ToolManager; public class VelocityToolsExample { public static void main(String... args) { Properties properties = new Properties(); properties.put("resource.loader", "classpath"); properties.put("classpath.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); Velocity.init(properties); ToolManager toolManager = new ToolManager(); toolManager.configure("tools.xml"); jsonToolSample1(toolManager); jsonToolSample2(toolManager); } static void jsonToolSample1(ToolManager toolManager) { // あとで } static void jsonToolSample2(ToolManager toolManager) { // あとで } }
2つ、サンプル的に用意しています。ここに、メソッド定義を埋めていきます。
設定ファイルは、このようにしました。
src/main/resources/tools.xml
<?xml version="1.0" encoding="UTF-8"?> <tools> <toolbox scope="application"> <tool key="json" class="org.apache.velocity.tools.generic.JsonTool"/> </toolbox> </tools>
なお、JsonToolでできるのは、JSONデータのパース(文字列、リソース)のみで、オブジェクトをJSONに変換するような
ことはできません。
さて、どういうシーンに使うのでしょう…。リクエストデータのJSONを、そのままViewで使ったりする時でしょうか?
そんなこと、ある?
まあ、気を取り直して…まずは、こんな感じ。
static void jsonToolSample1(ToolManager toolManager) { Context context = toolManager.createContext(); StringWriter writer = new StringWriter(); Velocity.mergeTemplate("templates/simple-json1.vm", "UTF-8", context, writer); System.out.println(writer.toString()); }
テンプレート。 src/main/resources/templates/simple-json1.vm
===== json sample 1 ===== #set($jsonString = " { ""string"": ""hello json"", ""number"": 100, ""array"": [1, 2, 3, 4, 5], ""object"": { ""key1"": ""value1"", ""key2"": ""value2"", ""object"": { ""foo"": ""bar"" } } } ") class = $json.class.name parse json literal = $json.parse($jsonString) #set($parsedJson = $json.parse($jsonString)) class = $parsedJson.class.name size = $parsedJson.size() get string = $parsedJson.get("string") get array index[0] = $parsedJson.get("array").get(0) get nested object = $parsedJson.get("object") class = $parsedJson.get("object").class.name get direct nested value = $parsedJson.get("object.key1") root = $parsedJson.root() class = $parsedJson.root().class.name
JsonTool.parseで、JSON文字列をパースすることができます。
少しずつ、結果を載せていきましょう。
class = $json.class.name parse json literal = $json.parse($jsonString)
結果。
class = org.apache.velocity.tools.generic.JsonTool parse json literal = {number=100, string=hello json, array=[1, 2, 3, 4, 5], object={key1=value1, key2=value2, object={foo=bar}}}
JsonTool#paserした結果は、thisが返るようなのでJsonToolになります。sizeは、そのオブジェクトのトップレベル…というか
"現在の階層の"プロパティの数。各要素にアクセスするには、プロパティの場合は名前を、配列の場合はインデックスを
指定します。
#set($parsedJson = $json.parse($jsonString)) class = $parsedJson.class.name size = $parsedJson.size() get string = $parsedJson.get("string") get array index[0] = $parsedJson.get("array").get(0)
結果。
class = org.apache.velocity.tools.generic.JsonTool size = 4 get string = hello json get array index[0] = 1
ネストしたオブジェクトは、1度取得してから操作することになります。
get nested object = $parsedJson.get("object") class = $parsedJson.get("object").class.name
ネストしたオブジェクトを取得すると、JsonContentになります。トップレベルであっても、JsonToolの内部にはJsonContentを
保持しています。
get nested object = {key1=value1, key2=value2, object={foo=bar}} class = org.apache.velocity.tools.generic.JsonContent
なお、JsonToolはネストしたオブジェクトのプロパティなどに直接アクセスすることはできません。
get direct nested value = $parsedJson.get("object.key1")
結果…です…。
get direct nested value = $parsedJson.get("object.key1")
JsonToolから、内部に持っているJsonContentを直接取り出すには、JsonTool#rootで。
root = $parsedJson.root() class = $parsedJson.root().class.name
結果。
root = {number=100, string=hello json, array=[1, 2, 3, 4, 5], object={key1=value1, key2=value2, object={foo=bar}}} class = org.apache.velocity.tools.generic.JsonContent
続いて、もうひとパターン。
Context context = toolManager.createContext(); context.put("jsonFile", "data.json"); StringWriter writer = new StringWriter(); Velocity.mergeTemplate("templates/simple-json2.vm", "UTF-8", context, writer); System.out.println(writer.toString());
今度は、テンプレート内でJSONファイルを読み出してみます。 src/main/resources/templates/simple-json2.vm
===== json sample 2 ===== class = $json.class.name read & parsed json literal = $json.read($jsonFile) #set($parsedJson = $json.read($jsonFile)) class = $parsedJson.class.name size = $parsedJson.size() get string = $parsedJson.get("string") get array index[0] = $parsedJson.get("array").get(0) get nested object = $parsedJson.get("object") class = $parsedJson.get("object").class.name get direct nested value = $parsedJson.get("object.key1") root = $parsedJson.root() class = $parsedJson.root().class.name
先ほどと異なるのは、JSONデータをStringで読むのではなく、JsonTool#readでファイルから読み出していることです。
read & parsed json literal = $json.read($jsonFile) #set($parsedJson = $json.read($jsonFile))
src/main/resources/data.json
{ "string": "hello json from file", "number": 100, "array": [1, 2, 3, 4, 5], "object": { "key1": "value1", "key2": "value2", "object": { "foo": "bar" } } }
JsonTool#readを使うと、ファイルシステムまたはクラスパス上のファイルを読むことができます。また、似たようなものに
JsonTool#fetchがあり、こちらはURLを指定してローカルまたはリモートのファイルを読むことができます。
結果は、先ほどの例とそう変わらないので、説明は省略。
class = org.apache.velocity.tools.generic.JsonTool read & parsed json literal = {number=100, string=hello json from file, array=[1, 2, 3, 4, 5], object={key1=value1, key2=value2, object={foo=bar}}} class = org.apache.velocity.tools.generic.JsonTool size = 4 get string = hello json from file get array index[0] = 1 get nested object = {key1=value1, key2=value2, object={foo=bar}} class = org.apache.velocity.tools.generic.JsonContent get direct nested value = $parsedJson.get("object.key1") root = {number=100, string=hello json from file, array=[1, 2, 3, 4, 5], object={key1=value1, key2=value2, object={foo=bar}}} class = org.apache.velocity.tools.generic.JsonContent
こんな感じで。
まとめ
相変わらず、ひっそりとリリースされていたApache Velocity Tools 3.0を試してみました。
Apache Velocity Engine 2.0から1年、やっと出てきたApache Velocity Tools 3.0ですが…。まあ、汎用的なテンプレートエンジン
として、使いたい方にはどうぞ、と。
個人的には、割と好きなテンプレートエンジンではあるのですけどね。