Magazine

vol.7

Japan Grails/Groovy User GroupContents
Series 14

Grails 2.3.0 新時代への幕開け。…………… 2
Series 10

Groovy 臨機応変（第二回）〜 indy で遊ぼう！
（但し Groovy 流に）〜… ………… 16
Series 15

組織内ルールや共通設定が自動適用される

独自 Gradle を作ろう… ………………………………… 27
Series 05

Grails Plugin 探訪〜第 8 回 Grails Markdown プラグイン〜… ………… 31
Information

リリース情報…………………………………………… 37

G*Magazine vol.7

Grails 2.3.0 新時代への幕開け。
14

series山本

剛（やまもと つよし／株式会社ニューキャスト）

出版・印刷関連のシステム設計開発等に従事するテクニカル DTP アーキテクト。
日本 Grails/Groovy ユーザーグループ名古屋支部長。2006 年より Grails のドキュメント翻訳、
その後、Grails 公式の Acegi プラグインを開発。書籍『Grails 徹底入門』( 翔泳社発行 ) の 9、10、11 章を執筆。

Grails 2.3.0 リリース。新時代への幕開け。
2013 年 9 月 10 日、Grails 2.3.0 がリリースされました。このバージョンでは次期バージョン 3.0 をターゲットに、大幅に改善・向上が行われています。例えば、以前から課題になっていた XSS 問

題を解決すべく GSP 関連のエスケーピングの考え方、Grails の振る舞いに適したリクエストバインディング、さらには今後 Web
アプリケーションには必須となる REST の実装、開発時の動作を改善するための仕組み改良などです。

この記事では、そんな次世代へ向けた Grails 2.3.0 の更新内容を、公式ドキュメントの内容を拝借しながら紹介したいと思います。

Grails 2.3.0 の更新内容
始めに Grails 2.3.0での更新概要を以下に示します。整頓すると、大まかに分けると五つの項目に分類できます。
コントローラ・ビュー• コントローラにネームスペース定義が可能に。
• コントローラ例外ハンドリング。

• フレキシブルで保守性の高く簡単な新データバインダー。
• リクエストボディをコマンドオブジェクトにバインド。
• ドメインクラスをコマンドオブジェクトとして使用。

• エンコーディング / エスケーピングの向上 - クロスサイトスク

新規プラグイン• Hibernate3 と 4 をサポート。

• スカッフォルディングがプラグインへ移動。
その中でも、今回（個人的にですが）注目しておきたいポイン

トは、REST 機能！と言いたいですが、やはり、いちばん実装に直結してくる、コントローラ・ビューとバインド廻りの実装だと思います。先ずはその辺りから追っていきましょう。

■コントローラ・ビュー実装が便利にそしてセキュアに●コントローラネームスペース定義

Grails は 2.3 以 前 で は、 例 え ば jp.grails.UserController と

jp.grails.admin.UserController のようにパッケージ違い同名称のコントローラを作成するとができませんでした。
（※元々できな
いと思ってるので同名称で作る事も無かったのですが）Grails 2.3 から「コントローラネームスペース定義」が実装されたことにより、別々のパッケージでの同じ名称のコントローラを使用できるようになりました。
使い方は以下のようになります。
以下、異なる二つの AdminController があるとします。それぞれに異なる名称の namespace プロパティを定義します。
package com.app.reporting // パッケージ違い

リプティング（XSS）防御を実装。

class AdminController {

REST

}

static namespace = 'reports' //namespace プロパティ• URL マッピングでリダイレクトが定義可能に。

// …

• サーバサイド REST サポート大幅改良。
開発支援• 依存管理の向上 - 依存管理エンジンを Aether に変更。

package com.app.security // パッケージ違い
class AdminController {static namespace = 'users' //namespace プロパティ• フォーク実行 - 全てのメジャーなコマンドが別々の JVM へ
フォーク。

• テストランナーデーモン。

• Unit テストのデフォルトが Spock に。

• デフォルトでの grailsw ラッパー生成。
コア機能• 非同期サポート - リクエストの非同期処理と GORM とシームレスに統合した新たな非同期プログラミング API。

2

Grails 2.3.0 新時代への幕開け。

// …

}
UrlMappings.groovy にて URL 定義するさいに namespace を指定します。

G*Magazine vol.7●コントローラはシングルトン
class UrlMappings {static mappings = {'/userAdmin' {controller = 'admin'
namespace = 'users'}'/reportAdmin' {controller = 'admin'
namespace = 'reports'}"/$namespace/$controller/$action?"()}}
リンクタグでは namespace 属性に指定することができます。
<g:link controller="admin" namespace="reports">
Click For Report Admin</g:link><g:link controller="admin" namespace="users">
Click For User Admin</g:link>

Grails 2.3 から、新規アプリケーション作成で、Config.groovy

での grails.controllers.defaultScope の指定が 'singleton' となっています。以前のバージョンまでは 'prototype' でした。

grails.controllers.defaultScope = 'singleton'
デフォルトがシングルトンになるので、アクションの実装はメ

ソッド推奨です。

一応ドキュメントの注意事項を、ここにも転記しておきます。

「コントローラのスコープは使用状況を考えてお使いください。

例えば、シングルトンのコントローラは、_ 全ての _ リクエストで共有されるためプロパティを持つべきではありません。デフォ

ルトで定義されているスコープの prototype を変更することで、プラグインなどで提供されたコントローラが protopype を前提で実装されている場合があるので注意しましょう。
」●新データバインダ

Grails 2.3 では、以前よりもフレキシブルで保守性の高くシン

プルなデータバインダを提供しています。このデータバインダの実装は今までの Spring を使用したの実装とは違い、Grails に必要なデータバインダとして新たに開発されています。もちろん下位互換として旧データバインダを使用する事も可能です。旧データ●コントローラ例外ハンドリング

コントローラアクションが投げた Exception をハンドリングするメソッドをコントローラに定義できるようになりました。例外
処理をコントローラ内で共通化するのに便利です。
package demo
class DemoController {def someAction() {// アクション実装}
def handleSQLException(SQLException e) {render 'SQLException をハンドリング '}バインダを使用するには、 grails-app/conf/Config.groovy に次のように指定します。

grails.databinding.useSpringBinder=true
では、何が追加されたか見ていきましょう。
フィールドごとのカスタム日付フォーマット

特定のフィールドに対して BindingFormat アノテーションで日付フォーマットを指定できます

import org.grails.databinding.BindingFormat
class Person {@BindingFormat('MMddyyyy')
Date birthDate}

def handleBatchUpdateException(
BatchUpdateException e) {redirect controller: 'logging',
action: 'batchProblem'}

グローバル定義として Config.groovy に設定することも可能です。次のようにマッチさせたいフォーマットをリスト順に渡します。

grails.databinding.dateFormats = ['MMddyyyy',
def handleNumberFormatException(
NumberFormatException nfe) {[problemDescription:'A Number Was Invalid']}}'yyyy-MM-dd HH:mm:ss.S',"yyyy-MM-dd'T'hh:mm:ss'Z'"]フ ィ ー ル ド に BindingFormat が 指 定 さ れ て い る 場 合 は、BindingFormat の内容が優先となります。

他 に、 日 付 に 関 し て は i18n/messages.properties を 使 用 し て

ローカライズ定義も可能です。例えば次の例では、i18n に定義
Grails 2.3.0 新時代への幕開け。

3

G*Magazine vol.7
した date.formats.birthdays の値からローカライズ別に判定してバインディングを行います。

class ZipcodeValueConverter implements
ValueConverter {# grails-app/conf/i18n/messages.properties
date.formats.birthdays=MMddyyyy@Override# grails-app/conf/i18n/messages_ja.properties

boolean canConvert(Object o) {o instanceof String

date.formats.birthdays=yyyyMMdd}

以下が使用方法。

@Overrideclass Person {Object convert(Object o) {@BindingFormat(code='date.formats.birthdays')def zips = o.split('-')

Date birthDate

return new Zipcode(zip3:zips[0],}zip4:zips[1])}ユーザ定義可能なデータコンバータ@Override

データコンバートを行うためには、内部的に自動で多くの自動型変換を行っていますが、アプリケーションの実装によっては独Class<?> getTargetType() {ンバータを定義できるようになりました。

}

return Zipcode

自の変換が必要となります。そのようなケースのためにデータコ仕組みとして簡単です。ValueConverter を実装したクラスを作成して、resources.groovy でビーン定義して、Spring コンテキス

トに登録するだけです。例として次のコードを見てみましょう。

（※サンプルコードに賛否両論あるとは思いますが。。。）
例えば次の２つのドメインクラスがあるとします。
class Address {Zipcode zipcode
String pref
String city}
コンバータを作成したらビーンの登録定義をします。ビーン名は zipcodeConverter としていますが何でも構いません。
beans = {zipcodeConverter ZipcodeValueConverter}

これで先程のようなデータコンバートが可能になります。
def address = new Address()}class Zipcode {String zip3

address.properties = [zipcode:'123-0001',
pref:' 東京都 ', city:' 品川区 ']String zip4
assert address.zipcode.zip3 == '123'
String toString(){
return "${zip3}-${zip4}"}

このようにユーザ定義データコンバータは、フォーム等からリ}クエストに投げられた内容を、特定したモデル型に対してコン

Address のデータバインドで、郵便番号 zipcode を "100-0001"

はめると、これでも最低限で済んでいると思いますが、少々コーのように文字列で受けた物を、Zipcode 側の zip3（３桁）と zip4（４桁）それぞれのフィールドに入れるとします。
def address = new Address()
address.properties = [zipcode:'123-0001',
pref:' 東京都 ', city:' 品川区 ']この動作でそれぞれのフィールドにバインドできるように

ValueConverter を用意します。コードの配置場所は src/groovy 以
下で問題無いです。

バートするのには便利な仕組みだと思います。ただ何もかも当て
ドが増えますね。

ユーザ定義フォーマットデータコンバータ

BindingFormat の 機 能 を 拡 張 す る こ と で、 簡 単 な デ ー タ

フォーマッタをユーザ定義実装することができます。これはFormattedValueConverter を実装することで、データバインド時に文字列などを加工することができます。

公式ドキュメントの例では、以下のコードのような、大文字小文字コンバートを例としています。

FormattedValueConverter の 実 装 ク ラ ス を 作 成 し ま す。Class

4

Grails 2.3.0 新時代への幕開け。

G*Magazine vol.7
getTargetType() で返す型に対してのコンバータとして認識されgroovy.grails.web.binding.GrailsWebDataBinder、org.grails.

String format）メソッドの２番目引数で format とあります。こは。

ます。このサンプルの場合は String 型です。def convert（value,の format 取得できる内容で分岐を記述して、それぞれの処理を実装します。BindingFormat アノテーションの引数が format で参照できる原理となっています。

import org.grails.databinding.converters.
FormattedValueConverterclass FormattedStringValueConverter implements
FormattedValueConverter {def convert(value, String format) {if('UPPERCASE' == format) {value = value.toUpperCase()} else if('LOWERCASE' == format) {value = value.toLowerCase()}value

databinding.ClosureValueConverter などをみてみるとよいので

クラス・フィールドごとのカスタムバインディング

BindUsing ア ノ テ ー シ ョ ン を 使 用 し て 特 定 の ク ラ ス ま た はフィールドに対して専用のバインディングを定義することができるようになりました。

特 定 の ク ラ ス に 対 し て は、BindUsing ア ノ テ ー シ ョ ン に、

BindingHelper を実装したクラスを指定してクラスに定義します。

以 下 の 例 は Grails ソ ー ス コ ー ド 用 の テ ス ト コ ー ド org.grails.

databinding.BindUsingSpec から拝借しました。

実装の概要は、各フォールド名がマッチしたら、それぞれ特定の演算を行う内容となっています。ClassWithBindUsing クラスは、
BindUsing アノテーションに MultiplyingBindingHelper を指定してあります。

@BindUsing(MultiplyingBindingHelper)}class ClassWithBindUsing {Integer leaveIt

Class getTargetType() {Integer doubleIt// specifies the type to which thisInteger tripleIt// converter may be applied
String}}こ ち ら の 実 装 コ ー ド も 先 程 の ValueConverter と 同 様 に、

resources.groovy に定義します。

}
MultiplyingBindingHelper は次のように、BindHelper の実装として作成します。

class MultiplyingBindingHelper implements
BindingHelper<Integer> {beans = {Integer getPropertyValue(Object obj,

formattedStringConverter FormattedStringValueConverter

String propertyName,}

DataBindingSource source) {def value = source[propertyName]

使用方法は次のように BindingFormat アノテーションに指定しdef convertedValue = value

ます。

switch(propertyName) {case 'doubleIt':

class Person {convertedValue = value * 2 // 値を２倍する@BindingFormat('UPPERCASE') // UPPERCASE での実装を処理

breakString someUpperCaseStringcase 'tripleIt':
convertedValue = value * 3 // 値を３倍する@BindingFormat('LOWERCASE') //LOWERCASE での実装を処理

breakString someLowerCaseString}
convertedValue

String someOtherString}

ここまでに説明してきた、これらの ValueConverter 系でのカスタムコンバートは、もちろん Grails のバインディングのコアで}}このコードを実行すると BindUsing での変換が行われて、結果は次のようになります。

ある部分とも同じ方式を使用しています。深い部分に興味がある
場合は Grails のソースを覗いてみるのも良いかもしれません。手始 め に org.grails.databinding.SimpleDataBinder、org.codehaus.
Grails 2.3.0 新時代への幕開け。

5

G*Magazine vol.7

def obj = new ClassWithBindUsing()class DemoController {obj.properties = [doubleIt: 9, tripleIt: 20,

def createWidget(Widget w) {leaveIt: 30]

render "Name: ${w?.name}, Size: ${w?.size}"}assert obj.doubleIt == 18 // 与えた値 9 に対しての２倍
assert obj.tripleIt == 60 // 与えた値 9 に対しての３倍}class Widget {assert obj.leaveIt == 30
この MultiplyingBindingHelper を使用するのはクラス全体への実装となりますが、特定のフィールドに対して BindUsing アノ
テーションを使用する場合は次のようになります。

BindUsing アノテーションの引数に、クロージャでコードを直接記述します。

class ClassWithBindUsingOnProperty {@BindUsing({obj,
source -> source['name']?.toUpperCase()})
String name

String name
Integer size}
リクエストがボディを含んでいるリクエストを curl などで実行。

$ curl -H "Content-Type: application/json"-d '{"name":"Some Widget","size":"42"}'
localhost:8080/myapp/demo/createWidget
結果はコントローラの render で返したようになります。
Name: Some Widget, Size: 42}
このコード例の結果は、toUpperCase と有るように name に与えられた内容は全て大文字となります。
デフォルトでの空文字列とトリミング

デフォルトで全ての空文字列はデータバインディングで null に変換されます。そして前後の空白をトリムします。これらの設定は Config.groovy 変更が可能です。デフォルトでは両方とオン（true）になっています。

// デフォルトは true です。
grails.databinding.trimStrings = false// デフォルト true です。
grails.databinding.convertEmptyStringsToNull =false

ドメインクラスをコマンドオブジェクトとして使用

同じく、でも若干異なりますが、
アクションのコマンドオブジェ

クトとしてドメインクラスを引数として定義されている状態で、リクエストパラメータに id が存在した場合は、自動的に id を使用してデータベースから、対象のドメインクラスインスタンスを取り出します。

次のような Person ドメインクラスがあったとします。
class Person {String name}
以下のように Person をアクションの引数に与えます。
class PersonController {def updatePerson(Person person) {println person●コマンドオブジェクト// リクエストパラメータに id が有ればリクエストボディをコマンドオブジェクトにバインド// データベースから自動取得。

コントローラアクションがコマンドオブジェクトを引数として定義されている状態で、リクエストがボディを含んでいる場合、ボディの内容はパースされコマンドオブジェクトにデータバイン
ドされます。この機能を使用すると、コマンドオブジェクトに対応した JSON また XML をリクエストボディとしての送信を受け取る等の実装が非常に楽になります。例として公式ドキュメントより。

次のように、コントローラとアクションの引数にコマンドオブジェクトを指定します。

6

Grails 2.3.0 新時代への幕開け。

}}
つまり、このドメインクラスを指定した場合の挙動では、def

updatePerson(Person person) で の、person は ド メ イ ン ク ラ ス
Person のインスタンスが必ず生成されます。

G*Magazine vol.7●エンコーディング / エスケーピングの向上

Grails 2.3 では専用の クロスサイトスクリプティング（XSS）

防御を実装しています。大まかには以下の内容となります。

• デフォルトで GSP エクスプレッションとスクリプトレットをフォルトではオフになっています。この設定を有効にした場合
は、staticparts の指定を 'raw' にする必要があります。

特定のプラグインに対して設定えお行う場合は、次のように例

HTML エスケーピング

えば Foo プラグインを対象の場合は、最初に foo. を付加します。

• 多重エンコーディング防止

foo.grails.views.gsp.codecs.expression = "none"• タグ固有のエンコーディング定義• GSP ページ内の全てのデータに対して安全と判断しない場合の自動エンコーディング

デフォルトが HTML エスケープされます

GSP での全ての ${} はデフォルトで HTML エスケープされるよ

うになりました。

信頼できる値をエスケープしないようにするには、raw() メ

ソッドを使用します。

${raw(page.content)}

ページ固有の定義

各 GSP ページに固有の定義も可能です。
<%@page expressionCodec="none" %>タグライブラリでのエンコーディング定義

各タグライブラリでは "defaultEncodeAs" プロパティを指定することで個別のコーデックを指定できます。

タ グ ラ イ ブ ラ リ ク ラ ス 全 体 に 定 義 す る 場 合 は、

エンコーディング / エスケーピング設定

defaultEncodeAs で指定します。

Grails 2.3では Config.groovy に以下の内容が追加されています。

static defaultEncodeAs = 'html'// GSP settings

各タグ（メソッド）に定義する場合は、encodeAsForTags でそ

grails {れぞれ定義することが可能です。

views {

static encodeAsForTags = [tagName: 'raw']

gsp {encoding = 'UTF-8'
htmlcodec = 'xml'
codecs {expression = 'html'
scriptlet = 'html'
taglib = 'none'
staticparts = 'none'}

また、タグを使用する際に指定することもできます。
<g:message code="foo.bar" encodeAs="JavaScript" />コード内で異なるエンコーディングに切り替える事も可能です。次の例は HTML タグは html コーデックのまま、Javascript のコードに対して Javascript コーデックを指定する例です。

}

out.println '<script type="text/javascript">'

filteringCodecForContentType {withCodec("JavaScript") {out << body()//'text/html' = 'html'}}}• expression - ${..} エクスプレッションを対象にしたコーデック}
out.println()
out.println '</script>'/>このように、細かな振る舞いができるようになり、より安全なの設定。

Web アプリケーションが構築可能です。まだデフォルトの設定対象にしたコーデックの設定。

ただ XSS に関して言うと今後の Web の進化と共にまだまだ問題• scriptlet - スクリプトレット（<% %>, <%= %> ブロック）を• taglib - タグライブラリを対象にしたコーデックの設定。タグを作成するさいに定義ができるのと下位互換のためデフォルトは none。

では完全とは言えませんが、下位互換を考えての事だと思います。
点も出てきそうですが、この Grails 2.3 からの実装では一安心といったとこでしょうか。

• staticparts - GSP 内の静的マークアップを対象にしたコーデッ
クの設定。

• filteringCodecForContentType - もっとセキュリティを高める
ために、全てのレスポンス出力に対しての指定もできます。デGrails 2.3.0 新時代への幕開け。

7

G*Magazine vol.7●URL マッピングでリダイレクトが定義可能に●ドメインクラスでの REST リソース定義

た。以下の例のように redirect: で指定します。

RESTFul API をもっと簡単に作成する方法が新機能として追加さ

URL マッピングでリダイレクトが指定できるようになりましclass UrlMappings {static mappings = {"/viewBooks"(redirect: '/books/list')

ドメインクラスに Resource アノテーションを指定するだけで、れています。次の例のように grails.rest.Resource と引数に対象の
uri 指定を追加します。

import grails.rest.Resource"/viewAuthors"(redirect:[controller: 'author', action: 'list'])"/viewPublishers"(redirect:@Resource(uri='/tasks')class Task {[controller: 'publisher', action: 'list',

String title

permanent: true])

Date period
Boolean done}

static constraints = {}period nullable:true

URL マッピングは今回のアップデートで他にも多くの追加実

done nullable:true

装があります。これからの Web アプリケーションに欠かせない
REST 関連の実装です。REST 関連の実装に関しては、記事の続きの REST 関連部分で紹介します。

■サーバサイド REST サポート大幅改良

Grails の REST 関連機能は大幅に改良され、さらに REST が身近で開発が容易になるような新機能が多数追加されています。
• ドメインクラスでの REST リソース定義。

• URL マッピングでの REST リソースマッピング用機能追加。
• シングルリソース、ネストリソース、バージョニング。

• RestfulController スーパークラス。

• 拡張可能なレスポンスレンダリングとバインディング API。
• REST コントローラのスカッフォルディング。
• HAL, Atom, Hypermedia（HATEAOS）対応。

REST サポートの実装内容はかなり広範囲になるので、深い部

分は今後機会があれば別で記事にするとします。今回は REST サ

ポート内容の一部概要を解説します。詳しくは公式ドキュメントを参考にしてください。有志による日本語ドキュメントプロジェ
クトで日本語版があります！ http://bit.ly/1bsfjJv
では、概要的に一部だけ紹介します。

}}
この指定をするだけで、REST リソースマッピングの設定とドメインと同じ名称のコントローラ（例の場合は TaskController）を、自動的に動的（※実ファイルでは無く）作成します。

例のように、@Resource(uri='/tasks') のみ指定すると JSON とXML 両方に対応した RESTful API を生成します。そしてデフォ

ルトでは XML を返すようになります。JSON を取得したい場合

は URL に Config.groovy の grails.mime.types に 設 定 さ れ て い る
JSON 識 別 用 拡 張 子 追 加 し ま す。 例 え ば http://localhost:8080/

example/tasks の 場 合 は、http://localhost:8080/example/tasks.
json となります。この指定は formats の指定をすることで順序を変更することが可能です。次のように json を先に指定すると拡張子なしで json を取得できます。

@Resource(uri='/tasks', formats=['json', 'xml'])// json を先にする
class Task {....
Grails のコンテントネゴシエーションの機能も連動しているた

め、コンテントタイプの指定は拡張子のみでは無く ACCEPT ヘッ
ダで指定することもできます。

curl -i -H "Accept: application/json" http://
localhost:8080/example/tasks
ACCEPT ヘッダで指定しても拡張子を指定した場合は拡張子が優先となります。

簡単な GET はもちろん他に POST（作成）,PUT（更新）,DELETE（削除）などメソッドを変えることで対象ドメインクラスを RESTfulに操作出来ます。

8

Grails 2.3.0 新時代への幕開け。

G*Magazine vol.7

curl -i -X POST -H "Content-Type: application/json" -d '{"title":" 色鉛筆を買って帰る "}'localhost:8080/example/tasks
curl -i -X PUT -H "Content-Type: application/json" -d '{"title":" 赤鉛筆を買って帰る "}'localhost:8080/example/tasks/1
curl -i -X DELETE localhost:8080/example/tasks/1
そ し て、 単 純 に ド メ イ ン 参 照 用 だ け の API に し た い 場 合 は

readOnly を指定することで読み取り専用にできます。
@Resource(uri='/tasks', readOnly=true) //readOnly を true にする
class Task {に使用できる機能の紹介です。
●URL マッピングでの REST リソースマッピング

先ほどのは機能は、ドメインクラスに @Resource(uri='/tasks')

のみ指定で URL マッピングを自動で設定してくれるという便利な物でしたが、直接 URL マッピングを定義することができます。
次のように UrlMappings.groovy に１行追加します。
"/tasks"(resources:"task")
この１行のみでいちばん単純な REST リソースマッピングを設定することができます。

どのような URL が実際に設定されたのかを確認してみます。

....

確認には、URL マッピングレポート用コマンド url-mappings-

ドメインクラスに１行指定する程度でできるとか簡単で便利でに、次のような内容が表示されます。（※このコマンドでは、ドすね。ただ、簡単に終わらせられる物だけでは無いので、いろいろな実装は必要と思いますが、それにしても必要最低限の機能は揃っている思います。ここから先はカスタマイズなどを行うとき

report を実行します。シェルコンソールの設定よってはカラフル
メインクラスに Resource アノテーションを付加した内容はリストされないようです。
）| URL Mappings Configured for Application| --------------------------------------Dynamic Mappings|*| /${controller}/${action}?/${id}?(.${format)?
|
*
| /
|
*
| ERROR: 500| Action: (default action) || View:/index|| View:/error|Controller: dbdoc|*| /dbdoc/${section}?/${filename}?/${table}?/${column}?

| Action: (default action) |Controller: task|
GET
| /tasks|
GET| /tasks/create|
POST| /tasks|
GET| /tasks/${id}|GET| /tasks/${id}/edit|
PUT| /tasks/${id}| DELETE | /tasks/${id}| Action: index| Action: create| Action: save
| Action: show
| Action: edit
| Action: update| Action: delete

|
|
|
|
|
|
|

内容を説明すると表になっている最初のカラムがメソッド、その次が ${id} などの変数を間に含んだ URL、そして最後が対象コ

ントローラでのアクション名になっています。開発の順番はそれぞれですが、先に UrlMappings.groovy へ必要な REST リソースマッピングを設定しておいて、レポートの内容を見ながら実装していく何てことも想像できます。

"/tasks"(resources:"task", excludes:\['delete', 'update'])
この簡単な resources: の指定だけでなく、他にも REST リソー

スマッピングの設定機能があります。

REST リソースマッピングでは includes また excludes を指定すシングルリソース

アクション index と show のみ。

けの resource: で指定すると意味が変わりシングルリソースの設ることで、指定した対象のみ、あるいは除外することが可能です。

"/tasks"(resources:"task", includes:\['index', 'show'])

更新削除系のアクション delete と update を除外。

先ほどの resources: 指定に似ていますが、"s" が無くなっただ

定になります。

"/info"(resource:'personalInfo')
次のようになります。

Grails 2.3.0 新時代への幕開け。

9

G*Magazine vol.7

Controller: personalInfo|
GET| /info/create|
POST| /info|GET| /info|GET| /info/edit|
PUT| /info| DELETE | /info| Action: create| Action: save
| Action: show
| Action: edit
| Action: update| Action: delete

|
|
|
|
|
|

最初の resources: との違いは ${id} の変数指定が含まれない状態になります。例えば単一な情報 API 用などに使用します。
ネストリソース

子リソースを持つ場合に使用します。
"/books"(resources:'book') {"/authors"(resources:"author")}
この指定をすると、次のような URL マッピングになります。
Controller: author|
GET| /books/${bookId}/authors|
GET| /books/${bookId}/authors/create|
POST| /books/${bookId}/authors|
GET| /books/${bookId}/authors/${id}|GET| /books/${bookId}/authors/${id}/edit|
PUT| /books/${bookId}/authors/${id}| DELETE | /books/${bookId}/authors/${id}| Action: index| Action: create| Action: save
| Action: show
| Action: edit
| Action: update| Action: delete

|
|
|
|
|
|
|

Controller: book|
GET
| /books|
GET| /books/create|
POST| /books|
GET| /books/${id}|GET| /books/${id}/edit|
PUT| /books/${id}| DELETE | /books/${id}| Action: index| Action: create| Action: save
| Action: show
| Action: edit
| Action: update| Action: delete

|
|
|
|
|
|
|

通常の URL マッピングも指定できます。
"/books"(resources: "book") {"/publisher"(controller:"publisher")}
次のような URL マッピングになります。
Controller: publisher|*| /books/${bookId}/publisher| Action: (default action) |Controller: book|
GET
| /books|
GET| /books/create|
POST| /books|
GET| /books/${id}|GET| /books/${id}/edit|
PUT| /books/${id}| DELETE | /books/${id}| Action: index| Action: create| Action: save
| Action: show
| Action: edit
| Action: update| Action: delete

10 Grails 2.3.0 新時代への幕開け。

|
|
|
|
|
|
|

G*Magazine vol.7
REST リソースのバージョニング

REST API の 実 装 バ ー ジ ョ ン を 増 や す な ど の 実 装 も URL マ ッ

ピ ン グ で 指 定 で き ま す。 一 般 的 な 例 と し て は、 次 の よ う に、
namespace: 指定をする方法があります。

"/books/v1"(resources:"book", namespace:'v1')"/books/v2"(resources:"book", namespace:'v2')
コントローラ側にも namespace の指定をすることで実装できます。

package myapp.v1
class BookController {static namespace = 'v1'

基本的には、この例のように記述すれば、必要な機能は動作します。いわゆる scaffold と同じような感覚です。実装をカスタマイズするには、カスタマイズ対象のアクションメソッドをオー
バーライドします。アクションの対応表をのせておきます。
GET
GET
POST
GET
GET
PUT
DELETE/books/books/create/books/books/$\{id}/books/$\{id}/edit/books/$\{id}/books/$\{id}indexcreate
save
show
edit
updatedeleteRestfulController について、詳しくは公式ドキュメントも参考にしてください。（http://bit.ly/1gDjyjc）

も ち ろ ん RestfulController を 使 用 し な く て も RESTful な コ}

ン ト ロ ー ラ は 開 発 可 能 で す。 今 ま で 通 り コ ン ト ロ ー ラ ア ク

package myapp.v2

常にわかりやすいので、是非そちらを参考にしてください。

ションを実装すれば良いわけですが、公式ドキュメントが非（http://bit.ly/18cI6yz）

class BookController {static namespace = 'v2'

●レスポンスレンダリング}

respond メソッド

Accept-Version ヘッダを使ったバージョンニングもサポートしステップ（http://bit.ly/18cI6yz）」の一部にも記載されている重ています。この場合は version: を指定します。

"/books"(version:'1.0', resources:"book", namespace:'v1')"/books"(version:'2.0', resources:"book", namespace:'v2')
次のように URL ではなく Accept-Version: 1.0 ヘッダでバージョンを指定してアクセスします。

curl -i -H "Accept-Version: 1.0" -X GET http://

公式ドキュメントの「REST コントローラの実装ステップバイ

要な部分で Grails 2.3 の新機能でもある「レスポンスレンダリング」。この機能がアクションからのレスポンスを返す重要な機能となっています。

アクションで使用する respond メソッドはリクエストのコン

テントタイプを判別して、JSON、XML、HTML などの適切なレスポンスを行います。この機能は今までも実装されていたコンテ

ントネゴシエーション機能の withFormat と似ていますが、より
RESTful な実装をスッキリと記述できるようになっています。

localhost:8080/myapp/books
バージョンの指定方法としては、ハイパーメディア /MIME タ

イプを使ったバージョニングに対応させることもできます。この辺りに関しては公式ドキュメントを参考にしてください。

// この１行でコンテントタイプを判別してレスポンスします。
respond Book.get(1)// formats の配列を指定するとその中から判別して// レスポンスします。

respond Book.get(1), [formats:['xml', 'json']]●RestfulController

REST リソースマッピングの方法がわかった所で、ここからは

使用方法は、先ず１つ目のパラメータは、レンダリング対象のRESTful コントローラ実装機能の話です。

オブジェクトで、２つ目にその他の引数を Map で渡します。そで追加されたスーパークラス RestfulController です。

model: , view: に関しては HTML でレンダリングする場合に使用

RESTful コントローラを実装するために便利なのが、Grails 2.3の他の引数には、formats: , model: , view: などを設定できます。

REST リソースに対してコントローラを実装するには、次のよします。

うに RestfulController の拡張を実装します。

class BookController extends RestfulController {static responseFormats = ['json', 'xml']
BookController() {super(Book)}

REST レンダリングカスタマイズ

XML・JSON の レ ン ダ ラ ー は grails.rest.render.xml , grails.rest.

render.json のパッケージ内にあり、これらは grails.converters.

XML と grails.converters.JSON を使用してレスポンスをレンダリングします。このレンダラーを使用してレスポンスのカスタマイズを行います。

}

Grails 2.3.0 新時代への幕開け。 11

G*Magazine vol.7

import grails.rest.render.xml.*
beans = {bookRenderer(XmlRenderer, Book) {excludes = ['isbn']}

考にすると、実装例としてわかりやすいと思います。
grails generate-async-controller example.Book
ドキュメントに多く記載されていますので、一部を見出しにそってダイジェストで紹介します。 公式ドキュメントはコチラ}

http://bit.ly/158V6kH

このようにビーンを追加してカスタマイズ実装します。他にも●Promise API

以前から XML・JSON コンバータのカスタマイズ方法が幾つか存在します。マーシャラレジスタ・ObjectMarshaller・コンバータ

API・AbstractRenderer・ContainerRenderer・GSP 使用など全部説明をすると少し話が長くなるので、詳しくは公式ドキュメント
を参照してください。

Grails 2.3 では、例外ハンドリングモデルや、非同期処理の連鎖、

リスナーの追加などの便利な機能を持つ、Promise の概念と統一されたイベントモデルを取り入れ並行プログラミングを簡単にする非同期機能を追加しました。その実装として

grails.async.Promises クラスを提供しています。

●REST コントローラのスカッフォルド

import static grails.async.Promises.*のスカッフォルド生成も準備されています。

promise を作成するには、grails.async.Promise インタフェース

とりあえず Grails 2.3 の REST を試したい場合は、もちろん REST

grails generate-async-controller example.Book
コードを書き出して参考にしてみると良いと思います。
●HAL, Atom, Hypermedia（HATEAOS）対応

Spring での API などのラッパーとしているのか、自分も勉強不足であまり聞き慣れていない、HAL・HATEAOS などに、Grails 2.3から対応しています。

HATEOAS と HAL に関しては以下を参照してください。

• HATEOAS - http://en.wikipedia.org/wiki/HATEOAS• HAL - http://stateless.co/hal_specification.html• Grails 公式ドキュメントから「アプリケーション状態エンジンのインタンスを返す task メソッドを使用します。

現在のスレッドをブロックした状態で処理を待つ場合はwaitAll メソッドを使用します。
def p1 = task { 2 * 2 }def p2 = task { 4 * 4 }def p3 = task { 8 * 8 }assert [4,16,64] == waitAll(p1, p2, p3)
スレッドをブロックしたくない場合は onComplete メソッドを使用します。

def p1 = task { 2 * 2 }def p2 = task { 4 * 4 }def p3 = task { 8 * 8 }としてのハイパーメディア」- http://bit.ly/15FDmkH

onComplete([p1,p2,p3]) { List results ->■非同期プログラミング API

Grails 2.3 では、Promise の概念と統一されたイベントモデルを取り入れることで、フレームワーク内での並行プログラミングを簡単にする非同期プログラミング API を提供しています。

（ ※ 公 式 ド キ ュ メ ン ト よ り 抜 粋 し て 紹 介 し ま す。 詳 し く は有志が翻訳をした日本語版ドキュメントを参照しましょう！
http://bit.ly/158V6kH ）今回追加された内容は、Grails 2.3 ドキュメントでの分類からみると以下の項目に分けられます。
• Promises• 非同期 GORM

• 非同期リクエストハンドリング「REST コントローラのスカッフォルド」でも解説しましたが、スカッフォルド生成ができますので、実際にコードを生成して参12 Grails 2.3.0 新時代への幕開け。

assert [4,16,64] == results}
def promiseList = tasks { 2 * 2 }, { 4 * 4}, { 8 * 8 }assert [4,16,64] == promiseList.get()

G*Magazine vol.7
Promise のチェーン

DelegateAsync 変換

す。途中のチェーンで例外が発生した場合に次のチェーンが呼ば場合において、DelegateAsync 変換を使用して同期 API を非同期

then メソッドを使用して promise をチェーンする事が可能でれることはありません。

final polish = { … }同じ API において、同期 API/ 非同期 API の両方が必要となる

API に変換することが可能です。
// サービス

final transform = { … }class BookService {final save = { … }List<Book> findBooks(String title) {final notify = { … }}Promise promise = task {}// 非同期 API - AsyncBookService として @DelegateAsync 追加// 長い実行タスク}

import grails.async.*

promise.then polish then transform then save then {class AsyncBookService {// 最終結果の呼出@DelegateAsync BookService bookService}}

Promise のリストとマップ●非同期 GORM

grails.async.PromiseMap のクラスとして実装されています。

ストアに対して、横断的に動作する非同期プログラミングモデル

リストとマップの概念を、ぞれぞれ grails.async.PromiseList 、tasks メソッドを使用して promise のリストやマップを作成できます。

def promiseList = tasks { 2 * 2 }, { 4 * 4}, { 8 * 8 }def promiseMap = tasks one:{ 2 * 2 },two:{ 4 * 4},
three:{ 8 * 8 }Grails 2.3 から、GORM でサポートされているすべてのデータを提供しています。

Async ネームスペース

非同期 GROM API は、すべてのドメインクラスに対し async

ネームスペースを通じて提供されます。

import static grails.async.Promises.*def p1 = Person.async.get(1L)Promise ファクトリ

def p2 = Person.async.get(2L)

Promises.promiseFactory の値を変更することで差し替える事がdef results = waitAll(p1, p2, p3)

Promise イ ン ス タ ン ス を 生 成 す る た め の フ ァ ク ト リ を、可能です。

import org.grails.async.factory.*

def p3 = Person.async.get(3L)

他にも非同期関連には多くの仕組みや注意点なども存在します。必ずドキュメントを一度読んでみましょう。

import grails.async.*
Promises.promiseFactory = new SynchronousPromiseFactory()

Grails 2.3.0 新時代への幕開け。 13

G*Magazine vol.7■開発支援・その他●依存管理の向上 - 依存管理エンジンを Aether に変更

Grails でデフォルトで使用されている依存管理エンジンが、Maven で使用されているエンジンの Aether に変更されました。
この変更は BuildConfig の設定を変更することで以前の依存管理
エンジン ivy に戻すことも可能です。

●フォーク実行

全てのメジャーなコマンドが別々の JVM へフォークされるよ

うになり、ビルドパスをランタイム / テストから分離します。
フォーク実行のパラメータは BuildConfig に定義できます。
grails.project.fork = [test: [maxMemory: 768, minMemory: 64,
debug: false, maxPerm: 256, daemon:true],grails.project.dependency.resolver = "maven" // or ivy// test-app 用 JVM への設定
run: [maxMemory: 768, minMemory: 64,

依 存 管 理 に Aether を 使 用 す る 事 で Grails で は Maven ビ ル ド

debug: false, maxPerm: 256],

ツールと同じ振る舞いをします。このことで以前と比べてスナッ// run-app 用 JVM への設定

プショットハンドリングの向上やカスタムパッケージング等の機

war: [maxMemory: 768, minMemory: 64,

能向上がはかられています。

debug: false, maxPerm: 256],

注意点として Aether では初期オフラインモードがありません。

// run-war 用 JVM への設定

Aether はフラットファイルから依存解決しないので、Maven セ

console: [maxMemory: 768, minMemory: 64,

ントラルからライブラリを取得します。GRAILS_HOME/lib で配

debug: false, maxPerm: 256]

布されたライブラリは最初の依存解決では使用されません。そのため一度 Maven セントラルリポジトリから取得するまでオフラ
インは使用できません。

// console 用 JVM への設定]

そしてさらに、dependency-report コマンドも改良され、依存問題の解決を手助けするために、依存関係のグラフがコンソールに表示されるようになりました。

runtime - Dependencies needed at runtime but notfor compilation (total: 107)+--- org.codehaus.groovy:groovy-all:2.1.6+--- org.grails:grails-plugin-rest:2.3.0|\--- org.slf4j:slf4j-api:1.7.5|\--- org.grails:grails-plugindatasource:2.3.0|\--- org.apache.tomcat.embed:tomcatembed-logging-log4j:7.0.42|\--- org.apache.tomcat:tomcatjdbc:7.0.42|\--- org.springframework:springjdbc:3.2.4.RELEASE|\--- org.grails:grails-web:2.3.0|\--- commons-collections:commonscollections:3.2.1|\--- taglibs:standard:1.1.2|\--- commons-fileupload:commonsfileupload:1.2.2|\--- xpp3:xpp3_min:1.1.4c|\--- org.grails:grailsdatabinding:2.3.0|\--- commons-el:commons-el:1.0|\--- javax.servlet:jstl:1.1.2|\--- org.springframework:springwebmvc:3.2.4.RELEASE|\--- opensymphony:sitemesh:2.4|\--- commons-beanutils:commonsbeanutils:1.8.3|\--- org.objenesis:objenesis:1.3|\--- org.grails:grails-spring:2.3.0|\--- com.google.code.gson:gson:2.2.4

14 Grails 2.3.0 新時代への幕開け。

●テストランナーデーモン

インタラクティブモードでのテストを実行時にバックグラウン

ドでデーモンが起動してテストがフォーク実行されテスト効率がアップします。デーモンはインタラクティブモードで restartdaemon コマンド実行すると再起動できます。
$ grails> restart-daemon
テ ス ト ラ ン ナ ー デ ー モ ン の 制 御 は、BuildConfig の grails.

project.fork で行います。 daemon: を false にすることでデーモンでのテスト実行を行わないように設定できます。
grails.project.fork = [test: [maxMemory: 768, minMemory: 64,
debug: false, maxPerm: 256, daemon:true],..
●その他の向上など

Unit テストのデフォルトが Spock に

Unit テストのデフォルトが Spock になりました。したがってspock が組み込まれているため、今後 spock プラグインは不要になります。Grails コマンドで生成されるテストコードのテンプ
レートも Spock 仕様になっています。

デフォルトでの grailsw ラッパー生成

create-app コマンドがデフォルトで grailsw ラッパーを生成するようになりました。ラッパーを生成しない場合は --skipwrapper オプションを指定してください。

grails create-app appname --skip-wrapper

G*Magazine vol.7
Hibernate3 と 4 をサポート

Grails 2.3 か ら プ ラ グ イ ン を 切 り 替 え る こ と に よ っ て

Hibernate3 と 4 の両方をサポートしています。
スカッフォルディング 2.0 プラグイン

コマンドを実行すると、もろもろ更新されますが、tomcat とhibernate のプラグインバージョンは自動更新されません。両プ
ラグインのバージョンを調整します。
plugins {//....

これまで長い Grails の歴史の中、重要な開発用ツールとして組

build ":tomcat:7.0.42"

み込まれていたスカッフォルディング機能が、Grails 2.3 からプ

runtime ":hibernate:3.6.10.1"

ラグインでの提供となりました。これは別に後ろ向きな事ではな// or ":hibernate4:4.1.11.1"

く、プラグインとして提供することでさらなる多様性が考えられると言うことです。このスカッフォルディングプラグイン 2.0 では、REST コントローラ、Async コントローラと Spock ユニットテ
ストをサポートしています。

■おまけ//....
}※ドキュメントによると upgrade コマンドは無くなり、今後は

use-current-grails-version（長い !）を使用する事になるとかいてありますが、そんな形跡はドキュメント以外に何処にも無く結局●upgrade コマンド !?

upgrade コマンドを使用することになります。

発とか、実装を重ねたアプリケーションでは無理でしょう。とはまとめ

既存アプリケーションをアップグレードする時に、コマンド１

思いますが。慎重に扱えば使っておくのも良いのでは？
一応一般的な手順です。

1. git など SCM でしっかり最新をコミットして起きましょう。

2. gvm u grails 2.3.0 を実行して手元の Grails のバージョンを変更。（gvm 使えない人は手動で Grails バージョンを変更）

3. grails upgrade コマンドを決め込む！

4. 差分をみて問題無ければベースはクリア。
まだ続きます。

Grails 2.3 がでて（執筆時 2013/9）すぐですが、やはり最初のバー

ジョンは、いつも難ありな感覚だと思います。記事がリリースされてる頃には、バグフィックス版の 2.3.1が出ていることかと思います。そして、2014 年の前半には、もう Grails 2.4 がでて、後半には Grails 3.0 へと向かっていきます。かなりの速度で進化して行

きますが Grails の根本は変わってません。新機能が多いと少し安

定度に不安がありますが、出たら少しずつ検証しながら、実際のプロジェクトで使っていくと良いでしょう。今後も最新情報を紹介できたらと思います。ではまた次回のバージョンアップで！

Grails 2.3.0 新時代への幕開け。 15

G*Magazine vol.7

Groovy臨機応変（第二回）〜indyで遊ぼう！（但しGroovy流に）〜10series

上原 潤二（うえはら じゅんじ）
NTT ソフトウェア株式会社 Grails 推進室所属。JGGUG（日本 Grails/Groovy ユーザ会）運営委員。
「Grails 徹底入門」（翔泳社）、「プログラミング GROOVY」（技術評論社）執筆メンバーの 1 人。
Groovy 技術に関するブログ「Gr な日々」を主宰している。

はじめにこんにちは、JGGUG の上原（NTT ソフトウェア株式会社所属）

Bytecode DSLということで、indy を扱うための手軽な方法として、Bytecodeです。Groovy 臨機応変の第二回目、今回のテーマは、「indy で遊DSL[4] を紹介します。これは Cedric Champeau 氏が 2011 年に公本記事のコードは Groovy 2.1.4 で動作確認をしています。JDK

ドのアセンブラ」であり、実装としては ASM ライブラリのラッ

ぼう !（但し Groovy 流に）」です。
は 1.7 以降が必要です。

indy って何？
Java 7 では、Java VM 上での動的言語の実行を効率化すること開を開始した「Groovy の内部 DSL で実現された Java バイトコー
パーです。以下は、Bytecode DSL のサイトにあるサンプルを元にした例です。

@GrabResolver(name="maven-repox", root="https://raw.github.com/uehaj/maven-repo/gh-pages/を目的とした一連の機能拡張（JSR 292: Supporting Dynamicallysnapshot")の機能拡張で追加された新規バイトコード命令「invokedynamic」

ast:0.2.0-separate-asm')

Typed Languages on the Java Platform）が導入されました。こ@Grab('groovyx.ast.bytecode:groovy-bytecode-にちなみ、この機能を愛称として indy と呼びます。

import groovyx.ast.bytecode.Bytecode

indy についてご存知の方は多いと思いますが、Java プログラ@groovyx.ast.bytecode.Bytecode

マが意識直接する機会はあまり多くは無いでしょう。なぜなら

int fib(int i) {んな Java コードを書こうとも indy 命令が生成されることはない

iconst_2て、lambda 式を使用すると indy 命令が使われるのですが、そのiload 1

しい資料 [2] もご参照ください）。

l1

indy の導入目的は、動的言語の処理系実装の効率化なので、どiload 1からです（しかしこの事情は Java 8 ではちょっと様相が違ってき

if_icmpge l1

件についてはブログ記事 [1] を書いてみました。宮川さんの素晴_goto l2
aload 0iload 1

いずれにせよ indy は、言語処理系のための機構であり、Java

プログラミングで意識する必要はほぼ無く、仮に遊びたいと思っ

iconst_2

析のためのライブラリである ASM ライブラリ [3] を使用すること

invokevirtual '.fib', '(I)I'出しとしてバイトコード命令列を構築する必要があるのでちょっiload 1て JasmineXT というのもありますが、invokedynamic には実際に

isubてもなかなか敷居が高いのです。例えば、バイトコード生成や解isubで indy 命令を含むクラスファイルを生成できますが、API の呼び

aload 0と手を出しずらい感があります。バイトコードのアセンブラとし

iconst_1

は対応していないようです。

invokevirtual '.fib' ,'(I)I'
iadd
l2

あるいはそんなことをせずとも、indy 対応の動的言語（Groovy

や JRuby）を使用すれば、内部的に indy 命令を含むバイトコードが生成されるのですが、残念ながら「遊んでいる感じ」が得られません。

ireturn}
println fib(40)
驚くべきことに、これは正しい Groovy コードであり以下のよ

16 Groovy 臨機応変（第二回）〜 indy で遊ぼう！（但し Groovy 流に）〜

G*Magazine vol.7

indy の基本

うに実行できます。

ここで indy/invokedynamic の動作について簡単に説明しよう$ groovy fib.groovyと思いましたが、簡単に説明するのが難しいので結構長いです。

102334155
上 記 コ ー ド 中 の「@Bytecode」 は、AST 変 換（groovyx.ast.

bytecode.Bytecode）の指定です。AST 変換は Groovy のコンパイ
ル処理に介在して機能追加したりできるのものですが、ここではコード生成フェイズを置換しているのです [5]。上記のコードは、
前述のように groovy コマンドで実行したり、groovyc でコンパイルして .class ファイルを生成することもできます。

詳細な説明は、Oracle のサイトにある invdy 関連の API リファレ
ンス [8] を見てください。

■従来の invoke 系命令によるメソッド呼び出し

ま ず、invokedynamic 以 前 の メ ソ ッ ド 呼 び 出 し 命 令 に は

invokevirtual, invokestatic, invokeinterface などがありますが、これらの命令を使ったメソッド呼び出しの様子を（図 1）に示しま

Bytecode DSL は本記事執筆時点で Maven Central リポジトリな

どにモジュールが登録されていないようですので、Grab で取得して試せるように筆者が少しだけ修正 [6] してコンパイルしたものを github 上にアップロードしておきました。上記のコード冒す。クラス名やメソッド名、引数のシグネチャなどによって指定された呼び出し先メソッドの参照が、ロード時もしくは呼び出し

時に Java のルールと機構を使って Java VM によって解決されて呼び出されます（（図 1）の（1））
。

頭の @GrabResolver 指定はそのための指定です。

ちなみに前述のコードは、フィボナッチ数を計算する
public int fib(int i) {return i<2?i:fib(i-2)+fib(i-1);
}

（図 1）

のような Java コードに対応するバイトコード列です。本稿では Java バイトコードについては説明しませんが詳細は Java 仮想
機械仕様 [7] などを参照ください。

■invokedynamic 命令によるメソッド呼び出し

これに対し、invokedynamic では呼び出し先メソッドは、言語処理系が提供するランタイムによって、その言語処理系のルール

Bytecode DSL はラベルや goto,tablejump などの命令にも対応しており、さらに重要なことに、invokedynamic 命令にも対応しに基づいて解決されます（（図 2）の（1））
。

メソッド参照を解決する方法を Java VM は知りません。

ているのです。これを使って遊んでみましょうというのが今回の記事の趣旨です。

（図 2）

そ の 代 り に、 す べ て の invokedynamic 命 令 に は、「Bootstrap

メソッド」と呼ばれるメソッドが結び付けられています（
（図 3）
の（2）
）
。Bootstrap メソッドは言語処理系のランタイムライブラ

リとして提供され、その言語処理系特有のメソッド選択のルールと機構を実装します。

Groovy 臨機応変（第二回）〜 indy で遊ぼう！（但し Groovy 流に）〜17

G*Magazine vol.7（図 5）

この結び付きは、1 つの invokedynamic 命令について 1 回しか（図 3）■Bootstrap メソッドによるメソッド解決

Bootstrap メソッドによるメソッド解決の様子を（図 4）に示します。まず、invokedynamic は「java.lang.invoke.MethodHandle（メソッドハンドル、以降 MH と略する）」を指すコンスタントプー

生じず、不可逆なので、以下のように invokedynamic が CallSiteに 置 き 変 わ る と 考 え て も 良 い か も 知 れ ま せ ん \[9]\。 た だ し、
CallSite オブジェクトは複数の invokedynamic 命令から共有され得ることに注意してください。Bootstrap メソッドから返される

CallSite オブジェクトが、シングルトン的に同じ CallSite のインス
タンスである、という実装方針も許容されるためです。

ル上のオブジェクトを介して Bootstrap メソッドと結び付いています（（図 4）の（1））。MH は invokedynamic で実現されるメソッ
ド呼び出し処理そのものにも用いられており、むしろその用途がメインです。MH はメソッド呼び出しやフィールド参照などの操作を抽象化したもので、メソッド呼び出しについて言えば、リフ
レクション API の java.lang.Method のようなものです。

（図 6）■メソッドの呼び出し

メソッド解決後の実際のメソッド呼び出しは以下のようにな り、CallSite/MH を 経 由 す る こ と を 除 け ば、invokevirtual や

invokestatic と同様の状態です。CallSite および MH を通じた呼び出しは Java VM が完全把握しており、処理系ランタイムのロジッ
クは一切介在しないので、JIT コンパイルの最適化がフルに効く（図 4）ことが期待されます。また、2 回目以降の呼び出しは以下の状態から始まります。

（図 4）における、メソッド解決までの処理の流れを以下に示します。

（1）Invokedynamic 命令の 初回実行時 に、Bootstrap メソッドの呼び出しが 1 回だけ 実行されます。

（2）言語処理系が提供する Bootstrap メソッドとしての「呼び出し先決定メソッド」が、型情報とメソッド名などを元に、適切な呼び出し先を決定します。

（3）Bootstrap メソッドは、決定された呼び出し先メソッドを参照する MH を含む CallSite オブジェクトを返します。

■CallSite の返却とインストール

Bootstrap が返した CallSite オブジェクトが、invokedynamic 命

令に結び付けられます（（図 5）の（1））。

（図 7）■CallSite の変更

最 後 に 重 要 な こ と と し て、CallSite#setTarget() の メ

ソ ッ ド 呼 び 出 し に よ り、MH を 指 し 変 え る こ と が で き ます。 但 し 抽 象 ク ラ ス で あ る CallSite を 継 承 し た ク ラ ス で あ る

MutableCallSite,VolatileCallSite クラスのインスタンスの場合のみです（（図 8）の（1））
。

18 Groovy 臨機応変（第二回）〜 indy で遊ぼう！（但し Groovy 流に）〜

G*Magazine vol.7
るでしょう、という例え話です。
invokedynamic 命令が CallSite で上書きされた後は、その命令のあった場所は「MH の参照先メソッドの呼び出し命令」としてJava VM に扱われます。Bootstrap メソッド呼び出しのオーバーヘッドは初回実行時のみにかかり、実際のターゲットメソッド（図 8）Groovy では metaClass の変更で発生するメソッドの差し替え

は、CallSite のターゲットの置換によって実現することができます。

の呼び出しについては ConstantCallSite ならオーバーヘッドは皆無となるでしょう。MutableCallSite や VolatileCallSite では MH の
間接参照のオーバーヘッドが残ります。しかしながら、Hotspot

JVM においては、
invokevirtual の仮想メソッドテーブルの参照（間接参照）経由のメソッド呼び出しがインライン展開され得るのと■理解のために、そして最適化の期待効果

invokedynaic 命令は、実質的には「Bootstrap メソッドの呼び出し命令」と考えることができます。そして「Bootstrap メソッ

ドの呼び出し命令」の呼び出しの結果得られる CallSite オブジェ

クトで invokedynamic 命令が上書き（自己書き換え）されます。
なおこの説明は、Java VM 上の作りとしてそうなっているということではなく、概念の理解のため例えばそう理解することもでき同じように、MH の間接参照経由のメソッド呼び出しがインライン展開されることを期待しても良いでしょう。Hotspot JVM で行

なわれる、外部クラスローディング時の最適化戻し（デオプティ
マイゼーション）と同等の処理が、CallSite の呼び出しターゲッ

トの変更によって行なわれると期待することにも無理はないでしょう。

使ってみよう indy&Bytecode DSL
では早速、Bytecode DSL で Indy を使ってみます。

■indy 呼び出し（例 1）と実行方法

まずは「Hello Indy」という文字列を表示するだけのコード例です。

（例 1）
1
2
3
4
5
6
7
8
9
10
11
12
13

@GrabResolver(name="maven-repo", root="https://raw.github.com/uehaj/maven-repo/gh-pages/snapshot")@Grab("groovyx.ast.bytecode:groovy-bytecode-ast:0.2.0-separate-asm")
import groovyx.ast.bytecode.Bytecode
import java.lang.invoke.CallSite
import java.lang.invoke.ConstantCallSite
import java.lang.invoke.MethodType
import java.lang.invoke.MethodHandle
import java.lang.invoke.MethodHandles.Lookup
import static org.objectweb.asm.Opcodes.H_INVOKESTATIC
class HelloIndy {

14
15

16
17
18
19
20
21
22
23
24
25
26 }

public static CallSite bootstrap( Lookup lookup, String methodName,
MethodType type) {assert methodName == 'xx'
MethodHandle mh = lookup.findVirtual(java.io.PrintStream, "println",
MethodType.methodType(void, [String]))
return new ConstantCallSite(mh)}@Bytecode
static main(args) {getstatic 'java/lang/System.out', 'Ljava/io/PrintStream;'
ldc 'Hello Indy'
invokedynamic 'xx', '(Ljava/io/PrintStream;Ljava/lang/String;)V',[H_INVOKESTATIC, 'HelloIndy', 'bootstrap', [CallSite, Lookup, String, MethodType]]
vreturn}

Groovy 臨機応変（第二回）〜 indy で遊ぼう！（但し Groovy 流に）〜19

G*Magazine vol.7
これを単に groovy コマンドで実行しようとすると以下のエラーが発生するかもしれません。
$ groovy HelloIndy.groovy

Caught: java.lang.ClassFormatError: Class fileversion does not support constant tag 15 in class

更できない CallSite である ConstantCallSite を作成し、返却しています。

この CallSite がインストールされることで、この Bootstrap メ

ソッドに紐付いた invokedynamic 命令（23 行目）は「println を呼び出す」処理に置き換えられることになります。

file HelloIndy

19@Bytecode

java.lang.ClassFormatError: Class file version

20

static main(args) {does not support constant tag 15 in class file21

'Ljava/io/PrintStream;'

HelloIndy
これは生成コードが indy 命令を含むため、ターゲットとする

クラスファイルのバージョンを Java7 に設定しなければならない

22■indy 呼び出し（例 1）の説明

以降（例 1）のコードを説明していきます。まず、
13 public static CallSite bootstrap(Lookup
lookup, String methodName, MethodType type) {ここは Bootstrap メソッドの定義です。Bootstrap メソッド引数

は以下のうち最初の 1 〜 3 が必須であり、さらに追加的な引数を取ることもできます。

1. Lookup lookup: MH を検索・取得するためのルックアップオ
ブ ジ ェ ク ト「java.lang.invoke.MethodHandles.Lookup」 が 与えられる。

2. String methodName: invokedynamic 命令で「メソッド名」として指定された文字列。これをメソッド解決にどのように使用するかは処理系に任されている。従って実体としてその「メソッド名」を持つ Java レベルのメソッドが存在する必要は全くない。例えば Grails の dynamic finder のようにこの引数をもとに処理内容を変化させも良いわけである。

3. MethodType type: 呼び出そうとするメソッド名の返り値と引数の型。

4. （オプション）追加的引数として、プリミティブ型の値（及びコンスタントプールの特定の種別のエントリ）を受けとることができる。

15

MethodHandle mh = lookup.findVirtual(java.io.PrintStream, "println",
MethodType.methodType(void, [String]))16

return new ConstantCallSite(mh)15 行 目 で は、 ル ッ ク ア ッ プ オ ブ ジ ェ ク ト を 使 っ てPrintStream#println() を参照する MH を取得しています。

16 行目では、その MH をターゲットとする、ターゲット先が変

invokedynamic 'xx', '(Ljava/io/
PrintStream;Ljava/lang/String;)V',[H_INVOKESTATIC, 'HelloIndy','bootstrap', [CallSite, Lookup, String,$ groovy -Dgroovy.target.bytecode=1.7 HelloIndy.
Hello Indy

ldc 'Hello Indy'23

ためであり、回避するには以下のようにします [10]。

groovygetstatic 'java/lang/System.out',

MethodType]]
24
25

vreturn}

26 }19 行目が Bytecode アノテーションの指定です。ここでは main

メソッドを bytecode で記述しています。

21、
22行目は引数の準備です。invokevirtual と同型なのですが、

21 行目では this にあたるオブジェクト（System.out）をスタックにプッシュ、22 行目では引数として文字列定数 "Hello Indy" をス
タックに積んでいます。

23 行目でいよいよ invokedynamic の登場です。基本的にやってることは Bootstrap メソッドの指定とその呼び出しについての情報の指定であり、一連の引数の意味は以下のとおりです。

• メソッド名（ここでは 'xx'）。Bootstrap メソッドに「メソッド名」
として渡る文字列。
実際にそのメソッドが存在する必要はない。

• invokedynamic で呼び出そうとするメソッドの引数と返り値の型（ こ こ で は '（Ljava/io/PrintStream;Ljava/lang/String;）V'）。
こちらは重要。

• Bootstrap メ ソ ッ ド を 特 定 す る 情 報。JVM 仕 様 の 4.7.21. The
BootstrapMethods attribute の bootstrap_methods[] で 使 用

さ れ る、4.4.8. The CONSTANT_MethodHandle_info Structureの CONSTANT_MethodHandle_info の 内 容 に 相 当 す る 情 報。
Bytecode DSL では以下のリストとして表現される。

• 第 1 要素（ここでは H_INVOKESTATIC）: Bootstrap メソッドを参照する MH の種別だが、H_INVOKESTATIC がほぼ一択。

• 第 2 要素（ここでは 'HelloIndy'）: Bootstrap メソッドが所属するクラスのクラス名• 第 3 要素（ここでは 'bootstrap'）: Bootstrap メソッド名• 第 4 要素（ここでは [CallSite, Lookup, String, MethodType]）：
Bootstrap メソッドの引数の型を表すリスト。追加的な引数があればその型を必要な個数分を追加指定する。

• （オプション）Bootstrap メソッドに渡す追加的な引数。

20 Groovy 臨機応変（第二回）〜 indy で遊ぼう！（但し Groovy 流に）〜

G*Magazine vol.7■indy 呼び出し（例 2）（例 1）では MH を 1 つだけ参照する ConstantCallSite を返す Bootstrap メソッドを使用しており、indy を使う意味が皆無に等しいものでした。次は MutableCallSite を使ってみた例です。文字列を出力するメソッドを invokedynamic を使って呼び出すのですが、
MutableCallSite を使って、「標準出力に表示するメソッド」と「ファイルに出力するメソッド」を切り替えています。
（例 2）
12 class HelloIndy2 {13
14

static void logToSysOut(String msg) {15
16

println(msg)
}

17
18

static void logToFile(String msg) {19
20

new File("output.log") << msg << "\n"
}

21
22

static CallSite cs

23
24

static MethodHandle methodSelect(Lookup lookup, String name) {25
26

return lookup.findStatic(HelloIndy2, name, MethodType.methodType(void, [String]))
}

27
28

public static CallSite bootstrap(Lookup lookup, String methodName, MethodType type) {29

MethodHandle mh = methodSelect(lookup, methodName)30

cs = new MutableCallSite(mh)31

return cs

32

}

33
34

@Bytecode35

static void test(String s) {36

aload 037

invokedynamic 'logToSysOut', '(Ljava/lang/String;)V',38

vreturn[H_INVOKESTATIC, 'HelloIndy2', 'bootstrap', [CallSite, Lookup, String, MethodType]]
39

}

40
41

static main(args) {42

test("output to sysout") // 標準出力に出力される

43

MethodHandle mh = methodSelect(MethodHandles.lookup(), "logToFile")

44

cs.setTarget(mh) // CallSite のターゲットをファイルへの出力を行うメソッドに置き換える45

test("output to file")46// ファイルに出力される

}

47 }

Groovy 臨機応変（第二回）〜 indy で遊ぼう！（但し Groovy 流に）〜21

G*Magazine vol.7
以降、解説します。まず、メソッド選択を行うメソッドを以下のように準備します。ここでは指定したメソッド名をもつ
HelloIndy2 クラスの静的メソッドから選択します。言語処理系を実装する際には、ターゲット言語のランタイムライブラリから、
メソッド呼び出しやフィールド値の参照をする MH を作ったり探してくる処理になるはずです。
24

static MethodHandle methodSelect(Lookup

さらに、例 1 では、ConstantCallSite を返していたところで30のように MutableCallSite() を作成して変数 cs に保存するようにします。この cs を使って
43

return lookup.findStatic(HelloIndy2, name,MethodType.methodType(void, [String]))

26}

MethodHandle mh =methodSelect(MethodHandles.lookup(),lookup, String name) {25

cs = new MutableCallSite(mh)"logToFile")
44

cs.setTarget(mh)で別のメソッドハンドルでターゲットメソッドの差し替えを行ないます。

■メソッドハンドルを加工する

indy の真骨頂は、私見ですが、メソッドハンドルの操作 API 群にあります。indy の用途、すなわち言語処理系の実装の文脈では、

invokedynaic 命令は「他言語」のメソッドの呼び出しであり、異なる言語セマンティクスの橋渡し処理をしなければならない場合があります。たとえば、• 言語 X でのリストデータ構造は、Java の java.util.List とは異なるため、メソッド呼び出し時にリストの引数や返り値を相互変換する• 言語 X のデータは、Java から見るとラッパーオブジェクトを介して扱う必要があり、メソッド呼び出し時に引数・返り値をラッピン
グ・アンラッピング変換する• 言語 X の実行コンテキスト（環境）を持ち回る必要があり、そのコンテキストを常にメソッドの第一引数に渡す必要があるなどのような場合です。indy においては、MH に対する高階操作、すなわち既存の MH を加工し「上記のような処理を追加的に実行 す る よ う な MH」を作り出すような API が多数 と り そ ろ え ら れ て い ま す [11]。 具 体 的 に は、 以 下 の MethodHandle およびMethodHandles の静的メソッド群です（主なもののみ抜粋）
。
クラス

メソッド

説明

java.lang.invoke.MethodHandle

asCollector

複数引数を配列で指定するような MH を得る

java.lang.invoke.MethodHandle

bindTo

最初の引数を固定した MH を得る

java.lang.invoke.MethodHandle
java.lang.invoke.MethodHandle

asSpreader
asTypejava.lang.invoke.MethodHandles

dropArguments

java.lang.invoke.MethodHandles

guardWithTest

java.lang.invoke.MethodHandles

permuteArgument

java.lang.invoke.MethodHandles

filterArguments

配列引数を複数引数で指定するような MH を得る
結果や引数をキャストや格上げなどをして適合させて呼び出すようなMH を得るいくつかの引数を捨てる MH を返す

引数それぞれに指定したフィルター MH を適用した結果を引数としてtarget となる MH を呼びだすような MH を返す

テスト用 MH と、テスト用 MH を実行した結果が真の場合に実行するMH と、偽の場合に実行する MH を渡し、その条件判断を実行する MHを返す
引数の順序を任意に変更した MH を返す

これらの機能で MH を複合的に組み合わせたものが invokevirtual に CallSite としてインストールされたときでも、単純な単一の MHの場合と同様に全体が依然として Java VM の完全な制御下にあり、高度な最適化（主にインライン展開）がなされることを期待できるのです（たぶん）。従来の Java VM 上の動的言語でも、CallSite 最適化は良くなされてきたわけですが、それらでは達成できなかったよ

うな性能向上を indy が生じさせる可能性はたぶんここにあります。言語セマンティクスの吸収層を、Java VM が良く把握可能な形で実装するということです。だとすると、Java との言語間のセマンティクスの差が少ない言語（Groovy とか）では性能向上の余地が少ない可能性もありますが、これは私の憶測です。

■メソッドハンドルの加工の例（bindTo）（例 1）を少しだけ変更して、PrintStream#println の第一引数（println はインスタンスメソッドなので this オブジェクトに対応する）に「System.out」を固定した MH をターゲットとする CallSite を Bootstrap メソッドから返すようにしてやります。

22 Groovy 臨機応変（第二回）〜 indy で遊ぼう！（但し Groovy 流に）〜

G*Magazine vol.7

1class HelloIndy3 {23public static CallSite bootstrap(Lookup lookup, String methodName, MethodType type) {4

MethodHandle mh = lookup.findVirtual(java.io.PrintStream, "println",
MethodType.methodType(void, [String])).bindTo(System.out)

5

return new ConstantCallSite(mh)

6

}

7
8

@Bytecode9

static main(args) {

10

ldc

11

invokedynamic 'xx', '(Ljava/lang/String;)V', [H_INVOKESTATIC, 'HelloIndy3','Hello Indy'

12

vreturn'bootstrap', [CallSite, Lookup, String, MethodType]]
13

}

14 }
4 行目で System.out を bindTo してやることで、10 〜 11 行目における呼び出しで System.out を引数として渡す必要がなくなりました。

■メソッドハンドルの加工の例（filterReturnValue）

2 つの MH を連続して実行するような MH を作成してみます（これが必要になる例を後で示します）。

MethodHandles#filterReturnValue は引数に与えた二つの MH（target, filter）を使い、target を呼び出した上でその結果の値を filter の引数に渡して呼び出し、その結果を返すような MH を返すメソッドです。その特別な場合として、target の戻り値の型が void、filter の引数が無しであれば、単に target, filter の順に MH を呼び出してくれます。これを利用すると 2 つの MH を順に呼びだす MH が作れます。
class HelloIndy4 {public static CallSite bootstrap(Lookup lookup, String methodName, MethodType type) {MethodHandle mh1 = lookup.findVirtual(java.io.PrintStream, "println",
MethodType.methodType(void, [String])).bindTo(System.out).bindTo("Hello")
MethodHandle mh2 = lookup.findVirtual(java.io.PrintStream, "println",
MethodType.methodType(void, [String])).bindTo(System.out).bindTo("Indy")
MethodHandle mh3 = MethodHandles.filterReturnValue(mh1, mh2)
return new ConstantCallSite(mh3)}@Bytecode
static main(args) {invokedynamic 'xx', '()V', [H_INVOKESTATIC, 'HelloIndy4', 'bootstrap',[CallSite, Lookup, String,MethodType]]
vreturn}}
ここでは bindTo() を二回呼び出して、println で出力する文字列も固定して引数なしの MH を作り出しています。
以下は実行例です。
% groovy-Dgroovy.target.bytecode=1.7

HelloIndy4.groovy
Hello
Indy

Groovy 臨機応変（第二回）〜 indy で遊ぼう！（但し Groovy 流に）〜23

G*Magazine vol.7

indy で Brainfuck を実装してみよう
最後に indy を使用する言語処理系を実装してみます。実装するのは Brainfuck という言語 [12] です。Brainfuck はいわゆる一つの奇妙なプログラミング言語ですが、処理系の実装が容易であることを重視して設計されたチューリング完全な言語であり、試しに実装してみるのには良いでしょう。

とはいえ、残念ながら Brainfuck は動的言語ではないので、あんまり indy が役にたちません。

そこで、一捻りとして、"++--" といった命令列を文字列として保持し、Bootstrap メソッドの実行時に「メソッド呼び出しの列を表現する MH」として生成してみます。"+" が p()、"-" が m() というメソッド呼び出しに対応するとすると、"++--" というオプション引数を受けとったならば、「p(), p(), m(), m(),」という一連の呼び出しに対応する MH を生成し、CallSite にして返すような Bootstrap メソッドを実装します。これによってクラスファイルのサイズが減少することを期待します。
以下が Brainfuck コンパイラのコード（compile.groovy）です。
// ネストしたループにおけるラベル名を管理するためのデータとコード。
def list = [].withDefault{0}def nestLevel = 0
def level = { it << list[0..nestLevel-1].join('_') }.asWritable()def increaseLevel = { list[nestLevel++]++; level(it) }.asWritable()def decreaseLevel = { level(it); nestLevel-- }.asWritable()// Brainfuck 命令を JVM バイトコードにコンバートする
def genCode = {new File(args[0]).text.replaceAll(/[\^\\\\+\\\\-\\\\<\\\\>\\\\.\\\\,\\\\[\\\\]]/, '').eachMatch(/[\^\\\\[\\\\]]+|[\\\\[\\\\]]/) { g0 ->if (g0 == '[') {it << """
_GOTO
tmp$increaseLevel
lab$level:"""}
else if (g0 == ']') {it << """
tmp$level:
getstatic'.data','[B'getstatic'.dp','I'
baloadifne
lab$decreaseLevel"""}else {
it << """
invokedynamic 'dummy', '()V', [H_INVOKESTATIC, 'Brainfuck', 'bootstrap',[CallSite, Lookup, String, MethodType, String]], '$g0'"""}}}.asWritable()println """\
@GrabResolver(name="maven-repo", root="https://raw.github.com/uehaj/maven-repo/gh-pages/snapshot")@Grab("groovyx.ast.bytecode:groovy-bytecode-ast:0.2.0-separate-asm")
import groovyx.ast.bytecode.Bytecode
import java.lang.invoke.*
import java.lang.invoke.MethodHandles.Lookup
import static groovyjarjarasm.asm.Opcodes.H_INVOKESTATIC
class Brainfuck {// Bootstrap メソッド
public static CallSite bootstrap(Lookup lookup, String methodName, MethodType type, String
instructions) {MethodHandle result = null
instructions.tr('<>.','lgo').each { insn ->MethodHandle mh = lookup.findStatic(Brainfuck, insn, MethodType.methodType(void.class))
result = (result == null) ? mh : MethodHandles.filterReturnValue(result, mh)}

24 Groovy 臨機応変（第二回）〜 indy で遊ぼう！（但し Groovy 流に）〜

G*Magazine vol.7}

new ConstantCallSite(result)// Brainfuck 実行のためのデータ構造
static int dp // データポインタ
static byte[] data = new byte[30000] // メモリ// Brainfuck 命令群
static void '+'(){data[dp]++}static void '-'(){data[dp]--}static void l(){dp--} // メソッド名が '<' だとクラスファイルとして違法なメソッド名になるので妥協
static void g(){dp++} // '>'static void o(){print((char)data[dp])} // '.'static void ','(){System.in.read(data, dp, 1)}@Bytecode
static void main(String[] args) throws Exception {// Brainfuck からコンバートされたコード$genCode
return}}"""
このコードは、Brainfuck 言語のソースファイルを引数として起動すると、Bytecode DSL を用いたアセンブラコードを含む Groovy コー

ドを標準出力に出力します。
以下は実行例です。

% cat hello.bf>+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.[-]>++++++++[<++++>-]<.>+++++++++++[<+++++>]<.>++++++++[<+++>-]<.+++.------.--------.[-]>++++++++[<++++>-]<+.[-]++++++++++.
% groovy compile.groovy hello.bf > a.groovy% groovy -Dgroovy.target.bytecode=1.7 a.groovy
Hello World!
上で a.groovy にはこんなコードが生成されています（抜粋）。
@Bytecode
static void main(String[] args) throws Exception {// Brainfuck からコンバートされたコード
invokedynamic 'dummy', '()V', [H_INVOKESTATIC, 'Brainfuck', 'bootstrap',[CallSite, Lookup, String, MethodType, String]], '>+++++++++'
_GOTO
tmp1
lab1:
invokedynamic 'dummy', '()V', [H_INVOKESTATIC, 'Brainfuck', 'bootstrap',[CallSite, Lookup, String, MethodType, String]], '<++++++++>-'
tmp1:
getstatic'.data','[B'getstatic'.dp','I'
baloadifne
lab1
invokedynamic 'dummy', '()V', [H_INVOKESTATIC, 'Brainfuck', 'bootstrap',[CallSite, Lookup, String, MethodType, String]], '<.>+++++++'
_GOTO
tmp2
lab2:
invokedynamic 'dummy', '()V', [H_INVOKESTATIC, 'Brainfuck', 'bootstrap',[CallSite, Lookup, String, MethodType, String]], '<++++>-':

Groovy 臨機応変（第二回）〜 indy で遊ぼう！（但し Groovy 流に）〜25

G*Magazine vol.7

まとめ
以上、かけ足でしたがいかがでしょうか。振り返るに、indy

は Java VM の JIT コンパイラのオープン化の一種です。JIT コンパ

イラの一部であった、メソッド選択機構の内部データ構造を SPI化し、フック等を通じて言語処理系から利用可能になるように公開したものです。

Java VM 上で言語処理系を実装するとき以外にはあまり役に立たないかもしれません。それ以外には、今いち用途が思いつきませんね…。

この記事が誰かの楽しみになりますことを希望しています。感想をお待ちしております（Twitter @uehaj）。

脚注・参考リンク[1] http://uehaj.hatenablog.com/entry/indyandlambda[2] http://www.slideshare.net/miyakawataku/lambda-meetsinvokedynamic[3] http://asm.ow2.org/[4] https://github.com/melix/groovy-bytecode-ast/wiki

http://www.jroller.com/melix/entry/yes_fibonacci_in_groovy_can

http://www.jroller.com/melix/entry/groovy_bytecode_ast_
transformation_released[5] Groovy++ でも、同じようにコード生成を置き変えることによって、静的 Groovy を実現していました。

[6] https://github.com/uehaj/groovy-bytecode-ast[7] http://docs.oracle.com/javase/specs/jvms/se7/html/[8] http://docs.oracle.com/javase/jp/7/api/java/lang/invoke_
package-summary.html[9] Java VM 仕 様 上 の 用 語 と し て は、 バ イ ト コ ー ド 列 中 の

invokedynamic 命令の出現のことを dynamic call site と呼びます。クラスとしての CallSite オブジェクトは、その意味での call site とはちょっと違う気がします。

[10] groovyc で は こ の プ ロ パ テ ィ の 設 定 で は タ ー ゲ ッ
トクラスファイルバージョンが変更できないため「configuration.setTargetBytecode("1.7")」という内容のファイルを作成し、--configscript オプションで指定する。

[11] この API 群を見ると、MH こそが Lambda だ、と思うのは私だけでしょうか？ MH だけでプログラミングができないか？

とも。でも「条件 MH が成立する間、ループ本体 MH を実行
するような MH を返す」などの重要な API がありません。（今のところは）そういうものじゃないのです。残念。

[12] http://ja.wikipedia.org/wiki/Brainfuck

26 Groovy 臨機応変（第二回）〜 indy で遊ぼう！（但し Groovy 流に）〜

G*Magazine vol.7

組織内ルールや共通設定が自動適用される
独自Gradleを作ろう

15

series林 政利（はやし まさとし）
フリーランスのエンジニアとして日々 Web 系システムを開発中。
G* 系の活動では Gradle のドキュメントを翻訳したり Grails のプラグインを公開したりしています。

こんにちは、LITERAL-ICE の林です。

G* の誇るビルドツール Gradle も最近は (Groovy というか主に

このビルドスクリプトは以下のようになっています。

Android 方面から ) よく名前を聞くようになってきており、興味// ./build.gradle

を持っておられる方も増えているのではと感じています。

configurations {さ て、 今 回 は「 組 織 で 使 う Gradle」 と い う 観 点 か ら、 既 に

runtimeGradle を触ったことがある方向けに、社内など組織内のビルド
ルールをある程度自動で共有する方法を紹介したいと思います。

}

社 内 リ ポ ジ ト リ の URL は こ こ に 書 い て る か ら build.gradle のdependencies {ジョン 1.8 はライセンスに問題があるから使わないでねなどと何}すね。

task showDependencies << {リプトで共有するようにしてみます。

println file.absolutePath }プ ロ キ シ の 設 定 は gradle.properties に 書 い て ど う の こ う の、

repositories セクションに追記して、あそうだライブラリのバー
処かに書く前に、その辺を自動化できないか、そういうお話しで
具体的には、本記事では以下の各設定を組織内の全ビルドスク• ビルドスクリプトの作成者も使用者も意識することなく社内リ
ポジトリを設定する。

• 同じように規定のプロキシ設定も自動適用する。

• あるライブラリやあるバージョンの使用を禁止する。

• あるライブラリを使用するときは、組織で決めた特定のバージョンを使用する。

このような各設定やルールの共有は、それらを入れ込んだ専用の Gradle を作り、それを使ってビルドさせることで簡単に実現

runtime name: "hoge-hoge", ext: "txt"configurations.runtime.each { File file ->}このスクリプトでは「"hoge-hoge.txt"」という依存関係を使用していますが、この依存関係の取得先であるリポジトリが設定されていません (repositories セクションがない )。

なので、公式の Gradle を使って ( システムの gradle コマンドなどで ) ビルドするとビルドに失敗します。

し か し、 同 梱 の ラ ッ パ ー「gradlew」 を 使 っ て

showDependencies タスクを実行すると以下のように問題なく結果が表示されるはずです。

できます。

> ./gradlew showDependencies

組織用の独自 Gradle を作る:showDependencies
xxxx\preconfigure-repository\lib\hoge-hoge.txt

ここでキーとなるのは「Gradle ラッパー」と「初期化スクリプ

ト」という Gradle の機能です。

これらについては後述しますが、まずは百聞は一見に如かずということで、リポジトリ設定済みの独自 Gradle を試してみましょう。

■社内リポジトリ設定済みの Gradle を使用する

以下にサンプルの Gradle プロジェクトを用意しました。

• https://github.com/literalice/gradle-sample-preconfigurerepository

BUILD SUCCESSFUL
つまり、ビルドスクリプトに何も書いてなくても、既にリポジトリが設定済みになっているわけです。

( ここでは、プロジェクトディレクトリの「lib」ディレクトリ

をリポジトリに設定しています )これを実現しているのが、Gradle の「Gradle ラッパー」および「初期化スクリプト」という機能です。

組織内ルールや共通設定が自動適用される独自 Gradle を作ろう

27

G*Magazine vol.7■初期化スクリプト

ウンロード先 URL を指定しています ( その他の設定はダウンロー

初期化スクリプトは、ユーザーがビルドを開始した際、その実ドした Gradle の保存先や解凍先です )。

初期化スクリプトは以下の方法でビルドに渡すことができ、ビという Gradle が指定されていることが分かると思います。

行前にあらかじめ実行されるスクリプトです。
ルド実行前に呼び出されて実行されます。

設定値を見ると、「gradle-1.7-preconfigure-repository-bin.zip」
これが、リポジトリ設定を同梱した独自 Gradle です。

独自 Gradle とは言っても、Gradle1.7 の「init.d」ディレクトリ

• gradle コマンド実行時に、オプションの -I か --init-script オプに「init.gradle」という初期化スクリプトを配置してアーカイブ• init.gradle と い う 名 前 の フ ァ イ ル を ホ ー ム デ ィ レ ク ト リ「wrapper/dists」にビルドに使用されたこの Gradle が保存されションに初期化スクリプトのパスを渡す。

しただけのものです。

の .gradle ディレクトリに置く。

ているので、確認してみてください。

• .gradle と い う 拡 張 子 の フ ァ イ ル を ホ ー ム デ ィ レ ク ト リの .gradle/init.d ディレクトリに置く。

• .gradle という拡張子のファイルを Gradle 本体の init.d ディレク
トリに置く。

// init.d/init.gradle
allprojects {repositories {flatDir {上から順番に実行されます。渡し方はたくさんありますが、こdirs "lib"

こで注目するのは一番下 (= もっとも優先されるスクリプト )、つ}まり Gradle 本体の「init.d」ディレクトリに初期化スクリプトを入れ込めるという点です。

■Gradle ラッパー

Gradle ラッパーは Gradle の中でもかなり有名な機能だと思います。この機能を使うと、Gradle をインストールしていないマシンでも Gradle ビルドを実行することができます。

}}
スクリプトの中で、リポジトリが一つ定義されています。

このスクリプトが、ビルド実行前に実行されたために、必要なリポジトリが設定されていたのです。

上記のスクリプトではフラットファイルリポジトリ設定でプロ

こ れ は、 プ ロ ジ ェ ク ト に 同 梱 さ れ た ラ ッ パ ー ス ク リ プ ト

ジェクトディレクトリの「lib」ディレクトリをリポジトリとし

ダウンロードし、その Gradle を使ってビルドを実行してくれるで設定することでその他のリポジトリを設定することもできまGradle ラッパーは Gradle が生成したものをプロジェクトに同(gradlew.bat またはシェルスクリプト gradlew) が Gradle 本体をて設定していますが、mavenCentral() や社内のリポジトリをここ

からです。

す。

梱するだけで非常に便利に機能しますが、今回ポイントとなる

プロキシ設定済みの状態で Gradle を使用させる

ロード先 URL は設定で変更することができる」という点です。

使用してできることをいくつか紹介していきます。

のは、「ラッパースクリプトがダウンロードする Gradle のダウン

先ほど実行した Gradle ビルドで確認してみます。

実行したファイル、「gradlew(.bat)」がラッパースクリプトで、ラッパーの設定ファイルはプロジェクトディレクトリの「gradle/
wrapper/gradle-wrapper.properties」ファイルです。

ここからは、初期化スクリプトと Gradle ラッパーの仕組みを

まず、社内プロキシなど、プロキシサーバーの設定です。ライ

ブラリを Maven リポジトリからダウンロードする際など、インターネット接続にプロキシを通す必要がある環境は多いと思います。

本来、gradle が使用するプロキシ設定は、プロジェクトディレ

gradleVersion=1.7-preconfigure-repositoryarchiveBase=PROJECT

クトリに「gradle.properties」を配置して、以下のように設定値を書き込めば適用されます。

archivePath=wrapper/dists
distributionBase=PROJECT

systemProp.http.proxyHost=localhost

distributionPath=wrapper/dists

systemProp.http.proxyPort=8080

zipStoreBase=PROJECT

systemProp.http.proxyUser=userid

zipStorePath=wrapper/dists

systemProp.http.proxyPassword=password

distributionUrl=https://dl.dropboxusercontent.

systemProp.http.nonProxyHosts=127.0.0.1|localhost

com/u/11287929/material/g-aster-7/gradle-1.7preconfigure-repository-bin.zip
一番下の設定値「distributionUrl」を見てください。

ここで、このビルドを実行するときに使用される Gradle のダ

28 組織内ルールや共通設定が自動適用される独自 Gradle を作ろう

一方、いちいち組織内の全ての gradle プロジェクトに設定するのが面倒くさい、または設定が変更されたときに簡単に追随したいという場合は、以下のように独自 Gradle の初期化スクリプ
トで設定しておくことができます。

G*Magazine vol.7// init.d/init.gradle

あるライブラリやあるバージョンの使用を禁止する
例えば、社内で開発しているライブラリが社内リポジトリに上System.setProperty("http.proxyHost", "localhost")
System.setProperty("http.proxyPort", "8080")
System.setProperty("http.nonProxyHosts","127.0.0.1|localhost")

がっているけれども、そのうちいくつかのバージョンについては使用させたくないとか、オープンソースライブラリのうちいくつかのバージョンからライセンスが変わったために社内規定で使用が禁止されたなどという場合に対応するための設定を紹介します。

allprojects {repositories {mavenCentral()}}
上記のスクリプトは、拡張子を .gradle にして独自 Gradle の「init.d」ディレクトリに同梱しておきます。

以下にサンプルプロジェクトを上げていますので、ローカルプ

ロキシなどを立てて試してみてください。

• https://github.com/literalice/gradle-sample-preconfigureproxy

サンプルプロジェクトで使用された独自 Gradle は、リポジ

ここでは、比較的身近な例と思われる iText ライブラリを例にします。

「AGPL に変更されたバージョン 5 系の iText をライセンス上の理由により使用させたくない」というパターンを想定してください。

ビルドスクリプトでこのライブラリが使用されている場合、例

外を投げてビルドを失敗させます。

サンプルプロジェクトを以下にアップロードしています。

• https://github.com/literalice/gradle-sample-forbiddenversions

このプロジェクトでは、以下のように、iText のバージョン 5 を使用しています。

トリ設定の例と同様、プロジェクトディレクトリの「wrapper/// ./build.gradleてください。

configurations {dists」に格納されています。中の初期化スクリプトを確認してみ
ちなみに、プロキシサーバーがない場合以下のようなエラーになるはずです。

> gradlew show --refresh-dependencies

runtime}dependencies {// runtime "com.lowagie:itext:2.1.7":showDependencies FAILEDFAILURE: Build failed with an exception.
* Where:Build file '~preconfigure-proxybuild.gradle' line:10* What went wrong:
Execution failed for task ':showDependencies'.
> Could not resolve all dependencies forconfiguration ':runtime'.
> Could not resolve org.apache.
commons:commons-lang3:3.1.
Required by::preconfigure-proxy:unspecified> Could not HEAD 'http://repo1.maven.org/
maven2/org/apache/commons/commons-lang3/3.1/
commons-lang3-3.1.pom'.
> Connection to http://localhost:12000
refused* Try:
Run with --stacktrace option to get the stack
trace. Run with --info or --debug option to get
more log output.

runtime "com.itextpdf:itextpdf:5.4.4"}
task showDependencies << {configurations.runtime.each { File file ->println file.absolutePath }}クローンして実行すると、以下のようにエラーが出力されるはずです。

> gradlew show
Execution failed for task ':showDependencies'.
> Could not resolve all dependencies forconfiguration ':runtime'.
> Could not resolve com.
itextpdf:itextpdf:5.4.4.
Required by::forbidden-versions:unspecified> Only version 2.+ or 4.+ are allowed for
iText.
一方、依存関係のバージョンを以下のように 2 系に変更すると、組織内ルールや共通設定が自動適用される独自 Gradle を作ろう

29

G*Magazine vol.7
エラーが発生することなくビルドを完了できます。
// ./build.gradle
dependencies {runtime "com.lowagie:itext:2.1.7"// runtime "com.itextpdf:itextpdf:5.4.4"}

ルールは推移的な依存関係にも適用されるので、この独自

Gradle を普通に使う限り iText のバージョン 5 が紛れ込むことはないでしょう。

ユーザーガイドには、この他にも依存関係解決ルールを使って実現できるパターンがいくつか紹介されています。

http://gradle.monochromeroad.com/docs/userguide/

dependency_management.html#sec:dependency_metadata_
manipulation

これらのルールも、独自 Gradle の初期化スクリプトで設定されています。今までの例と同じように、プロジェクトディレクト
リの「wrapper/dists」にビルドで使用しているディストリビュー

ションが格納されているので、中の初期化スクリプトを確認してみてください。

// init.d/init.gradle
allprojects {repositories {mavenCentral()}configurations.all {// 解決した全ての依存関係を走査する
resolutionStrategy.eachDependency {DependencyResolveDetails details ->final requested = details.requested• 禁止バージョンを検知したとき、上記のように失敗させるのではなく、別のバージョンに置換する• バ ー ジ ョ ン 番 号 を プ レ ー ス ホ ル ダ で 指 定 さ せ ("com.

lowagie:itext:*org-default*" など )、ルール内で社内データベースを参照して推奨バージョンに置換するな お、 依 存 関 係 解 決 ル ー ル は Gradle1.9 現 在「 試 験 的(Incubating)」としてマークされており、将来のバージョンで API等が変更される可能性があります。

変更される場合はリリースノートで通知されることになっていますので、もし現在使用している場合はリリースノートをよく確認されることをお勧めします。

まとめ
本記事では、Gradle ラッパーを使って、単に Gradle をインストールしていないマシンでビルドを実行させるだけでなく、初期
logger.lifecycle "library: {}", requested

化スクリプトや共通ルールを同梱した独自 Gradle をダウンロー
ドさせることで様々な処理を共有できることを紹介しました。

if (requested.name == "itext" ||requested.name == "itextpdf") {if(!(requested.version==~/^[2|4]\..+$/)){
throw new IllegalDependencyNotation("Only version 2.+ or 4.+ are allowed for iText.")
}
}
}
}
}
ここでは、「依存関係解決ルール」という Gradle の機能を使って全ての依存関係を走査し、iText の 2 系と 4 系以外が使用されている場合に例外を投げています。

30 組織内ルールや共通設定が自動適用される独自 Gradle を作ろう

さらに加えて依存関係解決ルールなどを使いこなせば、組織内で暗黙のうちに了解されていたり Wiki などに記載していたルールを上手くビルドスクリプトに反映させることができそうですね。

Gradle は開発、リリース速度が速く、先日も 1.9 がリリースされたばかりですが、一方で常に「エンタープライズ向け」という視点を保ちながら進化しています。Gradle の機能ライフサイクル
規定などからは、速度だけでなく、安定性にも気を遣って開発を進めたいという姿勢が感じられるかと思います。

もちろん、新しい機能を使っていこうとしたときは不安定なバグに遭遇することもありますが、組織内で検証など進めつつ、自動化できるところはどんどん Gradle で自動化して、イージーなライフをお楽しみいただければと思います。それでは。

G*Magazine vol.7

Grails Plugin 探訪
第8回~ Grails Markdown プラグイン ~URL: http://grails.org/plugin/markdown
プラグインのバージョン : 1.1.1

対応する Grails のバージョン : 1.3.5 以上

杉浦孝博
最近は Grails を使用したシステムの保守をしている自称プログラマ。
日本 Grails/Groovy ユーザーグループ事務局長。

共著『Grails 徹底入門』、共訳『Groovy イン・アクション』

はじめに今回ご紹介する Grails プラグインは、Grails Markdown プラグインです。

本記事は、次の環境で動作確認をしております。

• OS : Mac OS X 10.8.5• Java : 1.7.0_45• Grails : 2.3.2

なお、コマンドの実行結果については、紙面の都合上、出力結果を省略しており、実際の出力と異なる場合があります。ご了承願います。

Grails Markdown プラグインとはGrails Markdown プラグインは、Markdown 用のタグライブラ

リやサービスクラスを提供するためのプラグインです。タグライ
ブラリ、サービスクラスとも、Markdown を HTML に変換できます。

また、String クラスにメソッドを追加し、Markdown の文字列と HTML の文字列を相互に変換します。

なお、Markdown 処理のためのライブラリとして、Pegdownと Remark というライブラリを使用しています。

Markdown とはMarkdown とは、文書を記述するためのマークアップ言語の一つです。詳しくはウィキペディアを参照してください。

また、Markdown の文法については、このページを参照してください。

プラグインのインストール
Grails Markdown プラグインのインストールは、BuildConfig.

groovy に次のように記述することで行います。
plugins {....
compile ":markdown:1.1.1"}

タグライブラリ
タグライブラリを使うと、オン・ザ・フライで Markdown をHTML に変換します。

タグは、<markdown:renderHtml> です。

■タグのボディに Markdown を指定<markdown:renderHtml> タ グ の ボ デ ィ に Markdown 形 式の テ キ ス ト を 指 定 す る と、<markdown:renderHtml> と </markdown:renderHtml> で 囲 ま れ た 部 分 に 記 述 さ れ た 内 容 がHTML に変換されます。

<markdown:renderHtml> これは Markdown の * テスト * です。</markdown:renderHtml>

上記コードは次の HTML コードに変換されます。
<p> これは Markdown の <em> テスト </em> です。</p>Grails Plugin 探訪

第 8 回 ~ Grails Markdown プラグイン ~31

G*Magazine vol.7■タグの属性に Markdown を指定<markdown:renderHtml> タグの text 属性に Markdown 形式のテキストを指定すると、text 属性の値が HTML に変換されます。
<markdown:renderHtml text="** 別の ** Markdown のテストです。"/>

上記コードは次の HTML コードに変換されます。
<p><strong> 別の </strong> Markdown のテストです。</
p>■タグの属性に Markdown を記述したテンプレートファ
イルを指定<markdown:renderHtml> タグには、text 属性の他に template

属性を指定することができ、Markdown 形式のテキストを記述したテンプレートファイルを指定することができ、HTML に変換され取り込まれます。

テ ン プ レ ー ト フ ァ イ ル _readme.gsp に、 次 の よ う に<markdown:renderHtml> タグを含む内容を記述し、<p>String クラスの拡張
Grails Markdown プラグインは、String クラスを拡張し、次のメソッドを追加します。

• String markdownToHtml()• String htmlToMarkdown()■markdownToHtml メソッド

Markdown 形式の文字列を HTML 形式の文字列に変換します。
println " これは Markdown の * テスト * です。"
.markdownToHtml()
上記コードの実行結果は次のとおりです。
<p> これは Markdown の <em> テスト </em> です。</p>■htmlToMarkdown メソッド

HTML 形式の文字列を Markdown 形式の文字列に変換します。
println " これは Markdown の <em> テスト </em> です。"
.htmlToMarkdown()<markdown:renderHtml> これは Markdown の * テスト * です。</markdown:renderHtml></p><p><markdown:renderHtml text="** 別の ** Markdown のテストです。"/></p>

別の GSP ファイルから template 属性で上記テンプレートファ

イル readme.gsp を指定します。

<markdown:renderHtml template="readme" />実行結果は次の HTML コードに変換されます。

上記コードの実行結果は次のとおりです。
これは Markdown の * テスト * です。

サービスクラス
Grails Markdown プ ラ グ イ ン は、Markdown 処 理 用 に

MarkdownSerivice クラスを提供しており、markdownService という名前でコントロールクラスやサービスクラスにインジェクトできます。

class BookController {
....

<p>

def markdownService

<p>

....

<p> これは Markdown の <em> テスト </em> です。</p>String convertToHTML(String text) {

</p>

....

<p>

markdownService.markdown(text)<p><strong> 別の </strong> Markdown のテストです。</

....

p>
</p>
</p>
なお、template 属性と text 属性が両方とも指定された場合、

template 属性が優先されます。

}
また、markdownService は processor と remark という

プ ロ パ テ ィ を 提 供 し て お り、 そ れ ぞ れ、org.pegdown.

PegDownProcessor ク ラ ス の イ ン ス タ ン ス、remark は com.
overzealous.remark.Remark クラスのインスタンスとなります。

MarkdownService クラスは次のメソッドが定義されています。

• String markdown(def text, def conf = null)• String htmlToMarkdown(def text, def customBaseUri = "", defconf = null)• String sanitize(def text, def conf = null)

32 Grails Plugin 探訪 第 8 回 ~ Grails Markdown プラグイン ~G*Magazine vol.7■markdown メソッド

markdown メソッドは、Markdown 形式の文字列を HTML 形式の文字列に変換します。オプションで設定 ( 後述 ) を指定できます。

設定
Grails Markdown プ ラ グ イ ン は、 デ フ ォ ル ト の 設 定 以 外 に、Config.groovy に記述することで、またはメソッドの呼び出しの引数にマップの形式で値を指定することができます。

println markdownService.markdown(" これは Markdown の * テスト * です。")の実行結果は次のとおりです。
<p> これは Markdown の <em> テスト </em> です。</p>■テキストの折り返し
markdown.hardwraps = true// Config.groovy[hardwraps: true]// メソッドの引数

Markdown でテキストの折り返しをする場合、行の末尾にス■htmlToMarkdown メソッド

ペースを 2 つ置く必要があります。

Markdown 形式の文字列に変換します。

置くことなく、改行位置でテキストを折り返します。

htmlToMarkdown メ ソ ッ ド は、HTML 形 式 の 文 字 列 を

println markdownService.htmlToMarkdown(" これは Markdown の <em> テスト </em> です。")

hardwraps に true を設定した場合、行の末尾にスペースを 2 つ<markdown:renderHtml> これはMarkdown の * テスト * です。</markdown:renderHtml>の実行結果は次のとおりです。

というテキストに対し、hardwrap を true に設定した場合

これは Markdown の * テスト * です。

<p> これは <br/>Markdown の <em> テスト </em> です。</p>■sanitize メソッド

sanitize メソッドは、Markdown 形式の文字列をサニタイジン

グします。

println markdownService.sanitize(" これは Markdown の <em>* テスト *</em> です。")の実行結果は次のとおりです。
これは Markdown の * テスト * です。
また、
println markdownService.sanitize(" これは Markdown の <p>* テスト *</p> です。")の実行結果は次のとおりです。
これは Markdown の* テスト *です。

と出力され、hardwrap を false に設定した場合<p> これは Markdown の <em> テスト </em> です。</p>と出力されます。

■自動リンク
markdown.autoLinks = true// Config.groovy[autoLinks: true]// メソッドの引数

Markdown 形式のテキスト中に、http: や https: で始まる URL をリンクに変換します。

Markdown 形式の場合、リンクを出力するには次のように鍵括

弧と丸括弧を使用します。

<markdown:renderHtml>[Google](http://www.google.
co.jp/)</markdown:renderHtml>
次のように単純に記述された URL に対し、
<markdown:renderHtml>http://www.google.co.jp/</
markdown:renderHtml>
autoLinks を true に設定した場合<p><a href="http://www.google.co.jp/">http://www.
google.co.jp/</a></p>と出力され、autoLinks を false に設定した場合<p>http://www.google.co.jp/</p>と出力されます。

Grails Plugin 探訪

第 8 回 ~ Grails Markdown プラグイン ~33

G*Magazine vol.7■略語■スマートな引用符、句読点

markdown.abbreviations = true// Config.groovy[abbreviations: true]// メソッドの引数

Markdown 形式で略語の指定ができます。略語は <abbr> タグ

で囲まれます。

次のように Markdown 形式で記述した場合、// Config.groovy// メソッドの引数// Config.groovy// メソッドの引数// Config.groovy// メソッドの引数

引用符やハイフンを HTML エンティティに変換します。
次のように Markdown 形式で記述した場合、<markdown:renderHtml>
This is GSP.

<markdown:renderHtml>"Grails" --- 'Groovy'</markdown:renderHtml>*[GSP]: Groovy Server Pages</markdown:renderHtml>

smart を true に設定した場合

abbreviations を true に設定した場合<p>This is <abbr title="Groovy Server
Pages">GSP</abbr>.</p><p>&ldquo;Grails&rdquo; &mdash;&lsquo;Groovy&rsquo;</p>と出力され、smart を false に設定した場合と出力され、abbreviations を false に設定した場合<p>This is GSP.</p><p>*[GSP]: Groovy Server
Pages</p><p>"Grails" --- 'Groovy'</p>と出力されます。

■コードブロックと出力されます。

markdown.fencedCodeBlocks = true
[fencedCodeBlocks: true]■定義リストmarkdown.definitionLists = true// Config.groovy[definitionLists: true]// メソッドの引数

Markdown 形式で <dl> タグのリストを可能にします。
次のように Markdown 形式で記述した場合、<markdown:renderHtml>
Grails:markdown.smartQuotes = true[smartQuotes: true]
markdown.smartPunctuation = true[smartPunctuation: true]※両方とも true の場合の別の記法
markdown.smart = true[smart: true]

A rapid web-application development platform

for the JVM.
</markdown:renderHtml>
definitionLists を true に設定した場合<dl><dt>Grails</dt><dd>A rapid web-application// Config.groovy// メソッドの引数

Markdown 形式でそのままコードなどを表示する際、スペース

4 つのインデントを付ける必要がありますが、チルダを 3 つ、あるいはバッククォートを 3 つで囲むことで、同様のことができます。
次のように Markdown 形式で記述した場合、<markdown:renderHtml>~~~
Map<String, Object> map = new HashMap<String,
Object>();map.put("foo", 1);
map.put("bar", 2);~~~</markdown:renderHtml>
fencedCodeBlocks を true に設定した場合と出力され、definitionLists を false に設定した場合<pre><code>Map&lt;String, Object&gt; map = newHashMap&lt;String, Object&gt;();map.put(&quot;foo&quot;, 1);
map.put(&quot;bar&quot;, 2);</code></pre><p>Grails : A rapid web-application developmentと出力され、fencedCodeBlocks を false に設定した場合

development platform for the JVM.</dd></dl>

platform for the JVM.</p>と出力されます。

<p>~~~ Map&lt;String, Object&gt; map = newHashMap&lt;String, Object&gt;(); map.put("foo",1); map.put("bar", 2); ~~~</p>と出力されます。

34 Grails Plugin 探訪 第 8 回 ~ Grails Markdown プラグイン ~G*Magazine vol.7■テーブル
markdown.tables = true[tables: true]<p>| | Grouping || | First Header | Second Header// Config.groovy// メソッドの引数

Markdown Extra または Multimarkdown 形式で HTML テーブルを出力することができます。

次のように Markdown 形式で記述した場合、<markdown:renderHtml>||
Grouping||| First Header | Second Header | Third Header ||:------------ |:-------------:| ------------:|| Content|*Long Cell*||| Content|**Cell**|Cell || New Section |More|
Data || And more|
And more||</markdown:renderHtml>
tables を true に設定した場合<table><thead><tr><th align="left"> </th><th align="center" colspan="2">Grouping </th>
</tr>
<tr>
<th align="left">First Header </th><th align="center">Second Header </th><th align="right">Third Header </th></tr></thead><tbody><tr><td align="left">Content </td><td align="center" colspan="2"><em>Long Cell</em>
</td>
</tr>
<tr>
<td align="left">Content </td><td align="center"><strong>Cell</strong> </td><td align="right">Cell </td>
</tr>
<tr>
<td align="left">New Section </td><td align="center">More </td><td align="right">Data </td>
</tr>
<tr>
<td align="left">And more </td><td align="center" colspan="2">And more </td></tr></tbody></table>| Third Header | |:------------ |:------------:| ------------:| | Content | <em>Long Cell</em>|| | Content | <strong>Cell</strong> | Cell | |New Section | More | Data | | And more | And more||</p>と出力されます。

■全部入り
markdown.all = true// Config.groovy[all: true]// メソッドの引数

次に挙げる設定を一括で true または false にします。

• Hardwraps• Auto Links• Abbreviations• Definition Lists• Smart Quotes• Smart Punctuation• Fenced Code Blocks• Tables■HTML のタグの削除
markdown.removeHtml = true// Config.groovy[removeHtml: true]// メソッドの引数

Markdown 形式の文字列を HTML 形式の文字列に変換する際、HTML のタグを削除するかどうかを指定します。
次のようなコードがある場合、println " これは Markdown の <html><body><p>* テスト*</p></body></html> です。".markdownToHtml()
removeHtml を true に設定した場合<p> これは Markdown の <em> テスト </em> です。</p>と出力され、removeHtml を false に設定した場合<p> これは Markdown の <html><body><p><em> テスト </em></p></body></html> です。</p>と出力されます。

と出力され、tables を false に設定した場合

Grails Plugin 探訪

第 8 回 ~ Grails Markdown プラグイン ~35

G*Magazine vol.7

終わりに■テーブルの削除
markdown.removeTables = true// Config.groovy[removeTables: true]// メソッドの引数

HTML 形式の文字列を Markdown 形式の文字列に変換する際、テーブルのタグを削除するかどうかを指定します。
次のようなコードがある場合、println " これは Markdown の <em> テスト </em> です。これは <table><tr><td> テーブル </td></tr><table> です。
".htmlToMarkdown()
removeTables を true に設定した場合
これは Markdown の * テスト * です。これはと出力され、removeTables を false に設定した場合
これは Markdown の * テスト * です。これは<table><tbody><tr><td> テーブル </td></tr></tbody></table><table>です。
</table>と出力されます。

36 Grails Plugin 探訪 第 8 回 ~ Grails Markdown プラグイン ~Markdown は、GitHub の README や Tumblr な ど で も 採 用 され、さらに電子書書籍の入稿フォーマットとしても使っているところもあると聞きます。HTML が良い場合もあると思いますが、Markdown が適切なところでは、Grails Markdown とともに使用を検討してみてはいかがでしょうか。

G*Magazine vol.7

リリース情報 2013.11.17
GrailsGrails は、Groovy や Hibernate などをベースとしたフルスタックの Web アプリケーションフレームワークです。
URL: http://grails.org/
バージョン : 1.3.9, 2.1.5, 2.2.4, 2.3.2■更新情報• 2.1.5 では、ユニットテストの改良や GORM メソッドの実行
結果の改善、いくつかバグ対応が行われています。
• 2.1.5 リリースノート : http://grails.org/2.1.5+Release+Notes• 山本さんのブログ :http://d.hatena.ne.jp/mottsnite/20130429/1367230722• 2.2.4 では、いくつかバグ対応が行われています。
• 2.2.4 リリースノート : http://grails.org/2.2.4+Release+Notes• 山本さんのブログ :http://d.hatena.ne.jp/mottsnite/20130730/1375191304• 2.3.2 では、開発モードでドメインクラスの変更後セッショ
ンファクトリの最初期化を不可にできるようにしたり、生成されるテストコードが修正されたり、いくつかバグ対応が行
われています。
• 2.3.2 リリースノート : http://grails.org/2.3.2+Release+Notes• 山本さんのブログ :http://d.hatena.ne.jp/mottsnite/20131108/1383858545

GroovyGroovy は、JavaVM 上で動作する動的言語です。
URL: http://groovy.codehaus.org/
バージョン : 1.8.9, 2.0.8, 2.1.9, 2.2.0-rc-3■更新情報• 2.0.8 では、いくつかバグ対応が行われています。
• 2.0.8 リリースノート : http://jira.codehaus.org/secure/
ReleaseNote.jspa?projectId=10242&version=19099• 2.1.9 では、@CompileStatic を使用した際のバグを含め、いくつかバグ対応が行われています。
• 2.1.9 リリースノート : https://jira.codehaus.org/secure/
ReleaseNote.jspa?projectId=10242&version=19607• 2.2.0-rc-3 では、Groovysh で使用するクラスが移動され、いくつかバグ対応が行われています。
• 2.2.0-rc-3 リリースノート : http://jira.codehaus.org/secure/
ReleaseNote.jspa?projectId=10242&version=19632

Griffon
Griffon は、デスクトップアプリケーションを開発するためのア
プリケーションフレームワークです。
URL: http://griffon.codehaus.org/
バージョン : 1.4.0■更新情報• 1.4.0 では、ライセンスの自動パッケージ機能が追加された
り、InjectedResource アノテーションによるプロパティイン
ジェクションが改良されたり、いくつかバグ対応が行われています。
• 1.4.0 リリースノート : http://docs.codehaus.org/display/
GRIFFON/Griffon+1.4.0

Gant
Gant は、XML の代わりに Groovy で Ant タスクを記述し実行する
ビルド管理ツールです。
URL: http://gant.codehaus.org/
バージョン : 1.9.9

GMavenGMaven は、Maven 用の Groovy プラグインです。
URL: http://gmaven.codehaus.org/
バージョン : 1.4

GradleGradle は、Groovy でビルドスクリプトを記述し実行するビルド管理ツールです。
URL: http://www.gradle.org/
バージョン : 1.8■更新情報• 1.8 では、C/C++/ アセンブリに対応したり、実行速度や使用メモリが改善されたり、いくつかバグ対応が行われています。
• 1.8 リリースノート :http://www.gradle.org/docs/1.8/release-notes

GaelykGaelyk は、Groovy で記述する Google App Engine for Java 用のライトウェイトなフレームワークです。
URL: http://gaelyk.appspot.com/
バージョン : 2.0■更新情報• 2.0 では、GAE SDK 1.8.0 と Groovy 2.1.3 に対応し、新しい検索用 DSL が追加されたり、いくつかバグ対応が行われています。
• 2.0 リリースノート : http://gaelyk.appspot.com/download

Google App Engine SDK for Java
Google App Engine SDK for Java は、Java で Google App Engine
用の Web アプリケーションを開発するための SDK です。
URL: http://code.google.com/intl/ja/appengine/バージョン : 1.8.7■更新情報• 1.8.7 では、クラウド・エンドポイントが GA(General
Availability) となり、max_concurrent_requests 設定がバー
ジョン / モジュールごとに設定できるようになったり、いく
つかバグ対応が行われています。
• 1.8.7 リリースノート : http://code.google.com/p/
googleappengine/wiki/SdkForJavaReleaseNotes

GPars
GPars は、Groovy に直感的で安全な並行処理を提供するシステム
です。
URL: http://gpars.codehaus.org/
バージョン : 1.1.0GA■更新情報• 1.1.0GA では、LazyDataflowVariable や Promise ベースの APIが追加されたり、いくつかバグ対応が行われています。
• 1.1.0GA リリースノート : http://docs.codehaus.org/display/
GPARS/2013/07/25/Here+comes+GPars+1.1

Groovy++Groovy++ は、Groovy 言語に対して静的な機能を拡張します。
URL: http://code.google.com/p/groovypptest/
バージョン : 0.9.0

Spock
Spock は、Java や Groovy 用のテストと仕様のためのフレームワー
クです。
URL: http://code.google.com/p/spock/バージョン : 0.7

リリース情報37

G*Magazine vol.7

GroovyServ

GMetrics

GroovyServ は、Groovy 処理系をサーバとして動作させることでgroovy コマンドの起動を見た目上高速化するものです。
URL: http://kobo.github.com/groovyserv/
バージョン : 0.13

GMetrics は、Groovy ソースコードのサイズや複雑さを計算したり報告するためのツールです。
URL: http://gmetrics.sourceforge.net/
バージョン : 0.6■更新情報• 0.6 では、メトリクスやフューチャーが追加されたり、メト
リクスのインタフェースが変更されたり、いくつかバグ対応が行われています。
• 0.6 リリースノート :http://sourceforge.net/projects/gmetrics/files/gmetrics-0.6/■更新情報• 0.13 では、groovyclient でサーバの操作ができるオプションが追加されたり、GROOVYSERVER_HOST 環境変数がサポートされたり、いくつかバグ対応が行われています。
• 0.13 リリースノート :http://kobo.github.io/groovyserv/changelog.html

Geb
Geb は、Groovy を使用した Web ブラウザを自動化する仕組みです。
URL: http://www.gebish.org/
バージョン : 0.9.2■更新情報• 0.9.2 では、Navigator に isEnabled() と isEditable() が追加されたり、Grails 2.3 互換となったり、いくつかバグ対応が行われています。
• 0.9.2 リリースノート :http://www.gebish.org/manual/0.9.2/project.html#092

Easyb
Easyb は、 ビ ヘ イ ビ ア 駆 動 開 発 (Behavior Driven Development:
BDD) 用のフレームワークです。
URL: http://www.easyb.org/
バージョン : 1.5

Gmock
Gmock は、Groovy 用のモック・フレームワークです。
URL: http://code.google.com/p/gmock/バージョン : 0.8.3■更新情報• 0.8.3 では、Groovy 1.8.4 にアップグレードし、Grails 2.0 と互換がとられ、いくつかバグ対応が行われています。
• 0.8.3 リリースノート : http://grails.1312388.n4.nabble.com/
Release-of-gmock-0-8-3-td4646065.html

HTTPBuilder
HTTPBuilder は、HTTP ベースのリソースに簡単にアクセスするための方法です。
URL: http://groovy.codehaus.org/modules/http-builder/バージョン : 0.6.0

CodeNarc
CodeNarc は、Groovy 向けの静的コード解析ツールです。
URL: http://codenarc.sourceforge.net/
バージョン : 0.19
■更新情報

• 0.19 では、新しく 13 ルールが追加され、いくつかバグ対応が行われています。
• 0.19 リリースノート : http://groovy.329449.n5.nabble.com/
ANN-Announcing-CodeNarc-0-19-td5716250.html

GContracts
GContracts は、Groovy で契約プログラミングを行うためのフレームワークです。
URL: http://gcontracts.org/
バージョン : 1.2.12■更新情報• 1.2.12 のリリース内容は不明です。

GroovyFX
GroovyFX は、JavaFX を Groovy で書きやすくするためのフレームワークです。
URL: http://groovyfx.org/
バージョン : 0.3.1

GBenchGBench は、Groovy のためのベンチマーク・フレームワークです。
URL: http://code.google.com/p/gbench/
バージョン : 0.4.2■更新情報• 0.4.2 では、新しいシステムプロパティをサポートしたり、いくつかバグ対応が行われています。
• 0.4.2 リリースノート :https://code.google.com/p/gbench/wiki/ReleaseNotes042

Betamax
Betamax は、HTTP 通信の内容を保存し再生するテストツールです。
URL: http://freeside.co/betamax/
バージョン : 1.1.2

Caelyf
Caelyf は、Groovy で記述する Cloud Foundry 用のライトウェイト
なツールキットです。
URL: http://caelyf.cfapps.io/
バージョン : 1.1■更新情報• 1.1 では、Groovy 2.1.x に対応しました。
• 1.1 リリース issue: http://caelyf.cfapps.io/download

Vert.xVert.x は、非同期アプリケーション開発のためのフレームワーク
です。
URL: http://vertx.io/
バージョン : 2.0.2, 2.1M1■更新情報• 2.0.2、2.1M1 とも更新情報は不明です。

GVM (Groovy enVironment Manager)
様々な Groovy 関連のツールをインストールし、複数のバージョンを切り替えて使用するためのツールです。
URL: http://gvmtool.net/
バージョン : -38 リリース情報

■企業スポンサー■個人サポーター
須江 信洋 様関谷 和愛 様
田中

明様

個人サポータ制度のお知らせ
JGGUG では , 昨年に引き続き 2013 年度も個人サポータを募集いたします。.
個人サポータとなっていただいた方には、一年間にわたって JGGUG が発行する G* Magazine（年数回刊。基本的に電子版として配布予定）に個人サポータとしてお名前を掲載します（掲載を希望しない旨お申し出いただけば掲載しません）。
個人サポータとなるには、まず supporters@jggug.org にメイルで• お名前• 予定金額G* Magazine へのご芳名掲載の可否をお知らせください。追って、運営委員より振込先の情報などを返信します。
皆様のサポートをお待ちしております。

日本 Grails/Groovy ユーザーグループ
代表

山田 正樹

G* Magazine vol.7 2013.12
http://www.jggug.org

発行人：日本 Grails/Groovy ユーザーグループ
編集長：川原正隆
編集：G* Magazine 編集委員（杉浦孝博、奥清隆）
デザイン：㈱ニューキャスト
表紙：川原正隆
編集協力：JGGUG 運営委員会
Mail：info@jggug.org© 2013 JGGUG 掲載記事の再利用についてはCreative Commons ライセンスによります。

Publisher：Japan Grails/Groovy User Group
Editor in Chief：Masataka Kawahara
Editors：G* Magazine Editors Team
(Takahiro Sugiura, Kiyotaka Oku)
Design：NEWCAST inc.
CoverDesign：Masataka Kawahara
Cooperation：JGGUG Steering Committee
Mail：info@jggug.org