home ホーム search 検索 -  login ログイン  | help ヘルプ

find 検索

321 - 330 / 1320    [|<]  [|<]  [<]  31  32  33  34  35  36  37  38  39  40   [>]  [>|][>|]
タイトル/名前 更新者 更新日
日記/2013/03/23/今日の調査メモ : Groovy, Category, Mixin, ClassLoading msakamoto-sf 2013-03-23 22:17:55
Groovy/TemplateEngine/GroovyTemplates msakamoto-sf 2013-03-23 22:03:49
日記/2013/03/21/今日の調査メモ : JRebel maker buys Javeleon, Vaadin msakamoto-sf 2013-03-21 08:26:02
Groovy/お手軽Web開発(GroovyServlet, Java, Gradle, Tomcat) msakamoto-sf 2013-03-17 21:17:58
日記/2013/03/17/今日の調査メモ : Dynamic Java Class Reloading Libraries (JRebel, Javelelon, Dynamic Code Evolution VM) msakamoto-sf 2013-03-17 17:40:10
Groovy/Gradle/Tips msakamoto-sf 2013-03-17 11:24:19
Groovy/Gradle/Mixing Java and Groovy msakamoto-sf 2013-03-17 11:23:50
Groovy/Scripting/Tips msakamoto-sf 2013-03-10 00:40:56
Groovy/Debug/Object.dump(), inspect() msakamoto-sf 2013-03-09 23:47:51
Groovy/GroovyServ メモ msakamoto-sf 2013-03-09 23:17:17
ソート項目 / ソート順     1ページ 件ずつ表示

日記/2013/03/23/今日の調査メモ : Groovy, Category, Mixin, ClassLoading  

所有者: msakamoto-sf    作成日: 2013-03-23 22:15:15
カテゴリ: Groovy 

GroovyのCategoryとMixin周り:

実行時にObject.mixinできるってナニソレ怖い。

他、Groovyのドキュメントに動的にjarやクラスパスを追加する手法の解説があったのでメモ。


プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2013-03-23 22:17:55
md5:c3c75ab42310d786dd4c0d09bf24fce6
sha1:206a8d6118964e8dbe5107e3b0d640e7aea99937

Groovy/TemplateEngine/GroovyTemplates  

所有者: msakamoto-sf    作成日: 2013-03-23 21:32:56
カテゴリ: Groovy 

Groovyが提供しているテンプレートエンジン:

GStringTemplateEngineのTips

検証環境:

Win7 64bit
JDK 1.7 64bit
Groovy 1.8.9

Closureをbindしてテンプレートから使うには(1) : call()で明示的に呼ぶ

GStringTemplateEngineでは、テンプレートテキストは "groovy.tmp.templates.GStringTemplateScript[N]"([N]にはインクリメントされる数字が入る)のclosure内で処理されます。テンプレート内で

<%= dump() %>
<%= inspect() %>

すると以下のように出力されます。

↓↓"<%= dump() %>"の出力
<groovy.tmp.templates.GStringTemplateScript9$_getTemplate_closure1@73b05494 \
    delegate=groovy.lang.Binding@3d80fbe2 \
    owner=groovy.tmp.templates.GStringTemplateScript9@5f18d1f9 \
    thisObject=groovy.tmp.templates.GStringTemplateScript9@5f18d1f9 ...

↓↓"<%= inspect() %>"の出力
groovy.tmp.templates.GStringTemplateScript9$_getTemplate_closure1@73b05494

ということで、

def binding = [
    title : "...",
    c : { s -> ... },

とした場合、テンプレート中で

<%= c(title) %>

としても、「groovy.tmp.templates.GStringTemplateScript[N]にはc()なんてメソッドありません」とエラーになります。

これを回避するには、以下のように"call()"メソッドで明示的にclosureを呼び出します。

<%= c.call(title) %>

例:

@Grapes([
@Grab(group='org.apache.commons', module='commons-lang3', version='3.1'),
])

import org.apache.commons.lang3.*

String input_s = "<hello, 'bonjour' & \"evening\">"
def binding = [
    title : input_s,
    h1 : { s -> StringEscapeUtils.escapeHtml4(s).replace("'", '&#39;') },
    h2 : { s ->
        s.toString().replace('&', '&amp;').replace('<', '&lt;')
        .replace('>', '&gt;').replace('"', '&quot;').replace("'", '&#39;')
        },
]
println binding.h1(input_s)
println binding.h2(input_s)

def engine = new groovy.text.GStringTemplateEngine()
def text = '''\
Raw Title : [<%= title %>]
HTML Escaped Title(1) : [<%= h1.call(title) %>]
HTML Escaped Title(2) : [<%= h2.call(title) %>]
'''
def template = engine.createTemplate(text).make(binding)
println template.toString()

実行結果:

&lt;hello, &#39;bonjour&#39; &amp; &quot;evening&quot;&gt;
&lt;hello, &#39;bonjour&#39; &amp; &quot;evening&quot;&gt;
Raw Title : [<hello, 'bonjour' & "evening">]
HTML Escaped Title(1) : [&lt;hello, &#39;bonjour&#39; &amp; &quot;evening&quot;&gt;]
HTML Escaped Title(2) : [&lt;hello, &#39;bonjour&#39; &amp; &quot;evening&quot;&gt;]

Closureをbindしてテンプレートから使うには(2) : Object.mixinする

もう一つの方法は、"Object"クラスにテンプレートから使いたいメソッドをmixinしてしまう方法です。

@Grapes([
@Grab(group='org.apache.commons', module='commons-lang3', version='3.1'),
])

import org.apache.commons.lang3.*

String input_s = "<hello, 'bonjour' & \"evening\">"

class Helper {
    String h1(String s) { StringEscapeUtils.escapeHtml4(s).replace("'", '&#39;') }
    String h2(String s) {
        s.toString().replace('&', '&amp;').replace('<', '&lt;')
            .replace('>', '&gt;').replace('"', '&quot;').replace("'", '&#39;')
    }
}
Object.mixin(Helper)

def binding = [
    title : input_s,
]
println h1(input_s)
println h2(input_s)

def engine = new groovy.text.GStringTemplateEngine()
def text = '''\
Raw Title : [<%= title %>]
HTML Escaped Title(1) : [<%= h1(title) %>]
HTML Escaped Title(2) : [<%= h2(title) %>]
'''
def template = engine.createTemplate(text).make(binding)
println template.toString()

実行結果:

&lt;hello, &#39;bonjour&#39; &amp; &quot;evening&quot;&gt;
&lt;hello, &#39;bonjour&#39; &amp; &quot;evening&quot;&gt;
Raw Title : [<hello, 'bonjour' & "evening">]
HTML Escaped Title(1) : [&lt;hello, &#39;bonjour&#39; &amp; &quot;evening&quot;&gt;]
HTML Escaped Title(2) : [&lt;hello, &#39;bonjour&#39; &amp; &quot;evening&quot;&gt;]


プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2013-03-23 22:03:49
md5:0e7bbc9010d9641f3708e9fec3219c30
sha1:454b54cbc8b954085131f5c60a895058870a5d61

日記/2013/03/21/今日の調査メモ : JRebel maker buys Javeleon, Vaadin  

所有者: msakamoto-sf    作成日: 2013-03-21 08:22:25
カテゴリ: Java JavaScript 

日記/2013/03/17/今日の調査メモ : Dynamic Java Class Reloading Libraries (JRebel, Javelelon, Dynamic Code Evolution VM) で見かけたJRebelとJaveleonだが、先日、JRebel側がJaveleonを買収したみたい。

あと、こんなの見つけた。

JavaScriptとサーバサイドを組み合わせたリッチなインターフェイスのWebアプリ構築スタックらしい。extjsの仲間かと思ったが、サーバサイド側も含んでいるようなのでもっと複雑かもしれない。


プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2013-03-21 08:26:02
md5:2fa9c57750e9653c4ce7164810baf082
sha1:8dfb6d0510f3b9c2803d41e52c56af5823d3ee6d

Groovy/お手軽Web開発(GroovyServlet, Java, Gradle, Tomcat)  

所有者: msakamoto-sf    作成日: 2013-03-17 21:10:41
カテゴリ: Groovy Java 

Groovy/超お手軽Web開発(Groovy-1.8 + Jetty8, 201209版) でGroovyServletを使った非常にミニマルなWeb開発環境を紹介しました。今回はもう少し掘り下げて、実際にServletやJavaソースを組み合わせ、Tomcat上でclassファイルの自動リロード(Context auto reload)も有効にした「サクサク開発」が出来る構成を作ってみたので、紹介します。

サンプル:

ポイント:gradle-tomcat-plugin を使う + Java/Groovyクラスファイルの出力先を"/WEB-INF/classes/"以下に設定する。

gradle-tomcat-plugin:

検証環境:

Win7 64bit
JDK7 64bit
Gradle 1.4

サンプルの構成

以下のように、実際に開発の現場で使いそうなポイントを組み込んでいます。

  • "gradle tomcatRun" したあと、別のターミナルから"gradle classes"とかすれば、Tomcatがcontextをリロードしてくれるので「サクサク開発」が出来る。
    • 今回検証したのはコマンドラインとエディタを使った連携まで。EclipseやIntelliJ IDEAでも確実に「サクサク開発」を実践できるかまでは未検証。
  • JavaソースとGroovyソースを組み合わせている。(JavaソースからGroovyソースのクラスを参照している)
  • Java/GroovyコンパイラにJavaソースのバージョンとか文字コード指定、デバッグON/OFFフラグを設定している。

ということで、ソースの詳細についてはGitHubで眺めていただき、ポイントとなる部分だけを紹介していきます。

ポイント1 : Tomcatによるクラスファイル自動リロード ->「サクサク開発」

gradle-tomcat-pluginでは、"tomcatRun"タスクでTomcatを立ち上げる際に、Contextの"relodable"をデフォルトで有効化します。
これにより、"/WEB-INF/classes"および"/WEB-INF/lib"以下のファイルに変更があれば、Tomcat側で自動的にContextをリロードしてくれます。
ターミナルを3つ立ち上げ、1つは"gralde tomcatRun"でTomcatを起動させておき、2つ目ではエディタを立ちあげてソースファイルを編集し、3つ目で"gradle classes"を実行する、のような形で、コンパイルされたクラスを即座にTomcatに反映させる「サクサク開発」が実践出来ます。

ただし注意点が1つあります。GradleのJava/Groovyクラスファイル出力先はデフォルトでは以下のディレクトリです。

build/classes/...

また、warプラグインが想定するデフォルトの"/WEB-INF/"ディレクトリは以下になります。

src/main/webapp/WEB-INF/...

gradle-tomcat-pluginは、クラスファイルの出力先を設定から取得してContextに追加し、起動するため、基本的に上記のようなデフォルトのままでも起動自体は問題ありません。しかし、TomcatがContextのリロードをしてくれるのはあくまでも "/WEB-INF/classes" や "/WEB-INF/lib" の中が更新された場合であり、 "build/classes" 以下が更新されてもスルーしてしまい、Contextはリロードされません。

解決策として、以下のようにJava/Groovyクラスファイルの出力先を"src/main/webapp/WEB-INF/classes"に設定してしまいます。
build.gradle:

...

sourceSets.main.output.classesDir = 'src/main/webapp/WEB-INF/classes'

...

これにより、"gradle classes"すると "src/main/webapp/WEB-INF/classes" 以下にクラスファイルを出力してくれますので、Tomcat側で変更を検出し、Contextをreloadしてくれます。

また、このままですと"gradle clean"した時に "src/main/webapp/WEB-INF/classes" を削除してくれませんので、"clean"タスクを以下のようにカスタマイズします。

clean {
    // add customized class output path to deletion targets of 'clean' task.
    delete << 'src/main/webapp/WEB-INF/classes'
}

これにより、"gradle clean"すると "build/" 以下に加え、"/WEB-INF/classes" も削除してくれます(※ただし、上記cleanタスクのカスタマイズは、「ん~、こんな感じでイケんじゃね?」と試してみたらうまく行ってくれただけですので、もしかしたら厳密にはカスタマイズ方法勘違いしてるかもしれません。)

なお、あまりいじり過ぎたり何度もreloadが発生すると、Contextのreloadで以下のようなメッセージが表示されます。「怪しそうだな」と感じたら一旦Tomcatを停止して立ち上げ直すと良いのは、他のEclipseやIntelliJなどでの「サクサク開発」と同じです。

$ gradle tomcatRun
:compileJava UP-TO-DATE
:compileGroovy
:processResources
:classes
:tomcatRun
Started Tomcat Server
The Server is running at http://localhost:8090/warsample1
(...)
The web application [/warsample1] created a ThreadLocal with key of type \
[org.codehaus.groovy.reflection.ClassInfo.ThreadLocalMapHandler] \
(value [org.codehaus.groovy.reflection.ClassInfo$ThreadLocalMapHandler@64658ba0]) \
and a value of type [java.lang.ref.SoftReference] \
(value [java.lang.ref.SoftReference@46b1e8de]) \
but failed to remove it when the web application was stopped. \
Threads are going to be renewed over time to try and avoid a probable memory leak.
(...)

また、これで "gradle war" したwarファイルの中を覗いてみると、以下のようにクラスファイルのエントリが重複してしまっています。

$ jar tf build/libs/warsample1-1.0.0.war
...
WEB-INF/classes/net/glamenvseptzen/quickstart/
WEB-INF/classes/net/glamenvseptzen/quickstart/AdjustedGroovyServlet.class
WEB-INF/classes/net/glamenvseptzen/quickstart/HelloServlet.class
WEB-INF/classes/net/glamenvseptzen/quickstart/MyGroovyUtil.class
WEB-INF/classes/net/glamenvseptzen/quickstart/MyStringUtil.class
WEB-INF/classes/net/glamenvseptzen/quickstart/ToolKit.class
WEB-INF/classes/net/glamenvseptzen/quickstart/AdjustedGroovyServlet.class
WEB-INF/classes/net/glamenvseptzen/quickstart/HelloServlet.class
WEB-INF/classes/net/glamenvseptzen/quickstart/MyGroovyUtil.class
WEB-INF/classes/net/glamenvseptzen/quickstart/MyStringUtil.class
WEB-INF/classes/net/glamenvseptzen/quickstart/ToolKit.class
...

ただし、展開すればちゃんと一つのみになっていますので、ひとまず心配はいりません。実際に単独でセットアップしたTomcatにdeployし、正常に動作することを動作確認しております。

ポイント2 : JavaソースからGroovyのソースを参照

Groovy/Gradle/Mixing Java and Groovy のテクニックを使ってます。以下のように、mainとtestの両方の "SourceSet" でJavaのソース指定を空っぽにして、Groovy側のコンパイラでコンパイルするように調整をしています。
build.gradle:

...

[sourceSets.main, sourceSets.test].each {
    // compile java and groovy file at same time.
    it.groovy.srcDirs += it.java.srcDirs
    // disable java compilation
    it.java.srcDirs = []
}

...

ポイント3 : Javaソースのバージョン, 文字コード, デバッグ情報埋め込みの指定

GradleのJavaコンパイルのタスクも、Groovyコンパイルのタスクも、どちらも"Compile"タスクの型から派生しています。ということで、以下のようにすることでJava/Groovyの両方で共通してJavaソースのバージョン, 文字コード, デバッグ情報の埋め込みを設定できます。

tasks.withType(Compile) {
    sourceCompatibility = '1.7'
    targetCompatibility = '1.7'
    options.encoding = 'UTF-8'
    options.debug = true
}

その他参考情報など

EclipseとGraldeの連携という観点で色々と挑戦されているようです。

今回、"tomcatRun"まではgradle-tomcat-pluginのおかげでスンナリ動いてくれましたが、Contextのリロードについて "/WEB-INF/classes" 「しか」見ないということに気づかず、数時間以上「おかしい・・・なんで "build/classes/..." 以下のファイルはちゃんと更新されてるのに、Tomcat側で反映してくれないんだ・・・」と悩んでました。
gradle-tomcat-pluginの過去のIssueなどを漁っているうちに、"tomcatGradleExample"を見つけて「あれ~??こっちはやっぱりちゃんとリロードしてくれる・・・どこが違うんだ・・・?」と見比べているうちに「あ、こっちは"/WEB-INF/classes"に出力するようにカスタマイズしてる。もしかして・・・」とTomcatのドキュメントとかソースまで手繰り寄せ、「やっぱり、"/WEB-INF/classes|lib"以下しか決め打ちで見てないんだ・・・」と確認でき、それでようやく、「じゃぁカスタマイズするか~。あ、でも、"tomcatGradleExample"って"gradle clean"しても"/WEB-INF/classes" 以下に残っちゃうよな・・・cleanタスクもカスタマイズが必要だ。」となり、それでようやくなんとか安定して動くようになった次第です。

あと、一応サンプルにはGradle添付のJettyプラグインも使えるようにしてます。ただ、こちらではContextの自動リロードをしてくれなかったのでスルーしてます。なんかGradle添付のJettyプラグイン、設定出来るパラメータも少ないし、gradle-tomcat-pluginと比べると大分見劣りがしてしまう・・・。



プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2013-03-17 21:17:58
md5:a04cd8280eb579b066a4d98b11e4fd77
sha1:89591e826a6a9d9c8dd939277e320b19a3466984

日記/2013/03/17/今日の調査メモ : Dynamic Java Class Reloading Libraries (JRebel, Javelelon, Dynamic Code Evolution VM)  

所有者: msakamoto-sf    作成日: 2013-03-17 17:33:49
カテゴリ: Java 

Javaでもっと動的にクラスをリロードさせたい場合に、ClassLoaderにまつわるもろもろのノウハウが詰め込まれたライブラリやパッケージ等。

JRebel : 有償

JRebel関連記事:

Javeleon : 有償

Dynamic Code Evolution VM : 無償

  • Dynamic Code Evolution VM | A modification of the Java HotSpot(TM) VM that allows unlimited class redefinition at runtime.

プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2013-03-17 17:40:10
md5:8344cc901a4ef7b03f67a670677a90f1
sha1:8c2404880b2b2f3acd4063124e170ac7564bb124

Groovy/Gradle/Tips  

所有者: msakamoto-sf    作成日: 2013-03-11 00:02:16
カテゴリ: Groovy 
現在のバージョン : 2
更新者: msakamoto-sf
更新日: 2013-03-17 11:24:19
md5:d80c1172e771ea434243b3f03ccbb9bf
sha1:9707ad79a9cfd9ee2b9730bbba6eed7801650a03

Groovy/Gradle/Mixing Java and Groovy  

所有者: msakamoto-sf    作成日: 2013-03-17 00:10:29
カテゴリ: Groovy Java 

JavaとGroovyの混在したソースコードを扱うときの注意点

ポイント:JavaからGroovyを参照する時は、Groovy側と一緒にコンパイルされるようにする。

GradleではJavaコンパイラがまず実行され、続いてGroovyコンパイラ(内部的にはGroovyとJavaを一緒にコンパイルできるようになってる)が起動されます。そのため、Groovy側ソースのクラスを参照しているJavaソースがある場合、最初にJavaコンパイラが実行される時点ではGroovyのソースやクラスを認識できないため、参照先のGroovy側のパッケージやクラス名を解決出来ずエラーになります。なお、JavaのソースからGroovyを参照しておらず、あくまでもGroovyがJavaを参照しているだけであれば本記事で紹介しているような調整は不要です。
http://www.gradle.org/docs/current/userguide/groovy_plugin.html のタスク依存関係参照。)

解決策としては以下の様な対応方法があります。

  • 一番単純なのは "src/(main|test)/groovy" 以下にJavaのソースを置きます。これなら何も調整せずにGroovyコンパイラがJavaソースも同時にコンパイルしてくれます。
  • ディレクトリを分離しておきたい場合は、Groovyコンパイラが参照する "SourceSet" にJavaのソースが入ってるディレクトリを追加します。
    • この場合、Javaコンパイラが参照する "SourceSet" からGroovy側で参照するJavaソースディレクトリを外しておいてください。そのままにしておくと、Javaコンパイラ側でも処理されてしまいます。

サンプル:

検証環境:

  • Win7 64bit
  • JDK7
  • Gradle 1.4

サンプル解説 : java-refer-groovy-0 (失敗例)

サンプルコード:
https://github.com/msakamoto-sf/gradle-java-groovy-conjunction-demo1/tree/master/java-refer-groovy-0

Groovyのクラスを "src/main/java" のクラスから参照してます。参照先のGroovy側のパッケージやクラス名を解決出来ずにエラーになります。
"gradle -d"でデバッグログを有効にしてJavaコンパイラが起動するときの引数を確認してみると、当然ですが "src/main/groovy" 関連のパスはどこにも出て来ません。

23:37:22.253 [DEBUG] [org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler] Compiler arguments: \
-d (...)/build/classes/main \
-g \
-classpath (.../.gradle/...)/groovy-all-1.8.9.jar \
(...)/java-refer-groovy-0src/main/java/j1/JavaBean.java \
(...)/java-refer-groovy-0/src/main/java/j1/Main.java

サンプル解説 : java-refer-groovy-1 ("SourceSet"を調整)

サンプルコード:
https://github.com/msakamoto-sf/gradle-java-groovy-conjunction-demo1/tree/master/java-refer-groovy-1

build.gradleで以下のように調整し、GroovyコンパイラがJavaのソースを一緒にコンパイルしてくれるように調整してます。

sourceSets.main.java.srcDirs = []
sourceSets.main.groovy.srcDirs = ['src/main/groovy', 'src/main/java']
sourceSets.test.java.srcDirs = []
sourceSets.test.groovy.srcDirs = ['src/test/groovy', 'src/test/java']

sourceSets.(main|test).java.srcDirs から、Groovy側でコンパイルさせるJavaソースディレクトリを外しておくのを忘れないようにします。

サンプル解説 : java-refer-groovy-2 ("src/main/groovy"以下にJavaソース配置)

サンプルコード:
https://github.com/msakamoto-sf/gradle-java-groovy-conjunction-demo1/tree/master/java-refer-groovy-2

"src/main/groovy/" 以下にGroovyとJavaソースを配置してます。これによりJavaコンパイラは何も処理せずにスルーされ、Groovyコンパイラ側で一緒にコンパイルしてくれます。

参考



プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2013-03-17 11:23:50
md5:f6da9f944e2f8fd658fe7ca9843bb907
sha1:cc5c355af92dbc0e3042c63863f63071949e564a

Groovy/Scripting/Tips  

所有者: msakamoto-sf    作成日: 2013-03-10 00:32:12
カテゴリ: Groovy 

GroovyScriptとしてファイルに書いたのをそのままgroovyコマンドで実行するときのTips

共通コードをライブラリ化したい

多分オーソドックスなのは「共通コードはライブラリ化してjarにするだろJK」なのだろうけど、どうせ1-2つのクラスだけなんだろうし、それだけのためにjar作ってclasspathいじるのメンドイ、という時に、groovycでコンパイルしたクラスをそのまま同じディレクトリに放置しておくのもアリだなと思ってこんな感じにしました。

ライブラリ側:lib.groovy

@Grapes([
@Grab(group='org.slf4j', module='slf4j-api', version='1.7.2'),
@Grab(group='ch.qos.logback', module='logback-classic', version='1.0.9'),
])
import groovy.util.logging.*

@Slf4j
class C1 {
    static void m1() {
        println 'from m1:'
        log.trace 'trace2'
        log.debug 'debug1'
        log.info  'info1'
        log.warn  'warn1'
        log.error 'error1'
    }
}

@Slf4j
class C2 {
    static void m2() {
        println 'from m2:'
        log.trace 'trace2'
        log.debug 'debug2'
        log.info  'info2'
        log.warn  'warn2'
        log.error 'error2'
    }
}

これをコンパイルしておきます。

$ groovyc lib.groovy
$ ls
C1.class  C2.class  lib.groovy

groovycが"@Grape"も見てくれるのか、依存jarを指定する必要がないのがちょっと感動的です。

で、同じディレクトリにC1, C2を使うメインとなるGroovy Scriptを置きます。

main.groovy:

$ cat main.groovy
@GrabConfig(systemClassLoader=true)
@Grapes([
@Grab(group='org.slf4j', module='slf4j-api', version='1.7.2'),
@Grab(group='ch.qos.logback', module='logback-classic', version='1.0.9'),
])
import groovy.* // dummy

C1.m1()
C2.m2()

"@Grapes"と本体コードの間にダミーの"import"を入れてますが、これが無いといきなり"C1"で始まるのが、何がイケないのかわかりませんがsyntaxエラーで怒られました。
こっちでも同じ"@Grab"が必要なのと、こちらは実行側なので"@GrabConfig"の調整が必要だったりします。

あとはgroovyでもGroovyServのgroovyclientでも好きな方で実行してください。

$ groovy main.groovy
from m1:
00:38:33.909 [main] DEBUG C1 - debug1
00:38:33.913 [main] INFO  C1 - info1
00:38:33.914 [main] WARN  C1 - warn1
00:38:33.914 [main] ERROR C1 - error1
from m2:
00:38:34.030 [main] DEBUG C2 - debug2
00:38:34.030 [main] INFO  C2 - info2
00:38:34.030 [main] WARN  C2 - warn2
00:38:34.030 [main] ERROR C2 - error2

共通コードを変更した時はgroovycで再コンパイルが必要だったり、共通コードのファイル名を

xxxx.groovy

としたら、その中で

class Xxxx {

とするとなんかうまく全体として動いてくれないなど微妙な地雷臭はあったりしましたが、一応これはこれでアリといえばアリかなと。



プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2013-03-10 00:40:56
md5:5e1564cfd2b5099fc072cbefc8218901
sha1:212c35cfd7830a6445486c8b990c148f651d92f9

Groovy/Debug/Object.dump(), inspect()  

所有者: msakamoto-sf    作成日: 2013-03-09 23:44:02
カテゴリ: Groovy 

Groovyが拡張してくれたObject.dump()とinspect()が便利。
dump()はJavaのクラス名とか内部プロパティまで詳細情報を文字列で取得出来ます。
inspect()ですとフレンドリーな文字列表現を取得出来ます。

つまるところ、printlnとかロギングでのデバッグ出力で便利です。

例:t_collections.groovy ( http://groovy.codehaus.org/Collections から適当に練習用に抜き出した。)

def c1 = [1, 2, 3]
println '------------------------------------'
println 'dump()   : [' + c1.dump() + ']'
println 'inspect(): [' + c1.inspect() + ']'
c1 << 4
println '------------------------------------'
println 'dump()   : [' + c1.dump() + ']'
println 'inspect(): [' + c1.inspect() + ']'
c1 << [5, 6] << 7
println '------------------------------------'
println 'dump()   : [' + c1.dump() + ']'
println 'inspect(): [' + c1.inspect() + ']'

def c2 = [:]
println '------------------------------------'
println 'dump()   : [' + c2.dump() + ']'
println 'inspect(): [' + c2.inspect() + ']'
c2['name'] = 'abc'
c2.age = 20
def m1 = { you -> return "hello, ${you}." }
c2.greet = m1
println '------------------------------------'
println 'dump()   : [' + c2.dump() + ']'
println 'inspect(): [' + c2.inspect() + ']'
println c2.greet('bob')

def c3 = new Expando()
c3.name = 'Jon'
c3.greet = { "Good morning, ${name}" }
println '------------------------------------'
println 'dump()   : [' + c3.dump() + ']'
println 'inspect(): [' + c3.inspect() + ']'
println c3.greet();

実行:

$ groovy t_collections.groovy
------------------------------------
dump()   : [<java.util.ArrayList@7861 elementData=[1, 2, 3] size=3 modCount=1>]
inspect(): [[1, 2, 3]]
------------------------------------
dump()   : [<java.util.ArrayList@e93c3 elementData=[1, 2, 3, 4] size=4 modCount=2>]
inspect(): [[1, 2, 3, 4]]
------------------------------------
dump()   : [<java.util.ArrayList@36b936e8 elementData=[1, 2, 3, 4, [5, 6], 7] size=6 modCount=4>]
inspect(): [[1, 2, 3, 4, [5, 6], 7]]
------------------------------------
dump()   : [<java.util.LinkedHashMap@0 header=null=null accessOrder=false table=[null] size=0 threshold=0 loadFactor=0.75 modCount=0 useAltHashing=false hashSeed=-1854095574 entrySet=[] keySet=null values=null>]
inspect(): [[:]]
------------------------------------
dump()   : [<java.util.LinkedHashMap@2029ac47 header=null=null accessOrder=false table=[greet=t_collections$_run_closure1@1a16ff7a, age=20] size=3 threshold=1 loadFactor=0.75 modCount=3 useAltHashing=false hashSeed=-1854095574 entrySet=[name=abc, age=20, greet=t_collections$_run_closure1@1a16ff7a] keySet=null values=null>]
inspect(): [['name':'abc', 'age':20, 'greet':t_collections$_run_closure1@1a16ff7a]]
hello, bob.
------------------------------------
dump()   : [<groovy.util.Expando@4c48b2f8 expandoProperties=[name:Jon, greet:t_collections$_run_closure2@38dddee8]>]
inspect(): [{name=Jon, greet=t_collections$_run_closure2@38dddee8}]
Good morning, Jon


プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2013-03-09 23:47:51
md5:a85a4c83ac01a1dbcbb5cac6ddac4bff
sha1:fee5f73ffb9e92789a100e8f27137c0608108908

Groovy/GroovyServ メモ  

所有者: msakamoto-sf    作成日: 2013-03-09 23:03:02
カテゴリ: Groovy 

公式 : http://kobo.github.com/groovyserv/index.html

Windowsでのインストール

インストーラもありますが、win用のバイナリのzipファイルが配布されてますので、そちらを展開して環境変数を調整するだけでもOKです。というかそちらの方法しか試してません。

自分はCygwin使いですので、Cygwinの.bashrcでこんな感じにしてます。

# Groovy
GROOVY_HOME=/cygdrive/c/work/apps/groovy-1.8.9
export PATH=$GROOVY_HOME/bin:$PATH

# GroovyServ
GROOVYSERV_HOME=/cygdrive/c/work/apps/groovyserv-0.11
export PATH=$GROOVYSERV_HOME/bin:$PATH
alias gr='groovyclient'

"GROOVYSERV_HOME"は本来は不要で、binにpathが通ってればオッケーなんですが、見た目が揃ってるので入れてます。また、"groovyclient"もタイピングが長いので"gr"にalias設定してます。

使い方

まずgroovyserverを起動します。

$ groovyserver
Groovy home directory: /cygdrive/c/in_vitro/devtools/groovy-1.8.9
Groovy command path: /cygdrive/c/in_vitro/devtools/groovy-1.8.9/bin/groovy (found at GROOVY_HOME)
GroovyServ home directory: /cygdrive/c/in_vitro/devtools/groovyserv-0.11
GroovyServ work directory: /home/FengJing/.groovy/groovyserv
Original classpath: (none)
GroovyServ default classpath: /cygdrive/c/in_vitro/devtools/groovyserv-0.11/lib/*
Starting....
groovyserver 224(1961) is successfully started

あとはGroovyスクリプトを書いて、groovyclientで実行するだけです。

groovyserverを止めたい場合は"-k"付きで実行します。

$ groovyserver -k
Groovy home directory: /cygdrive/c/in_vitro/devtools/groovy-1.8.9
Groovy command path: /cygdrive/c/in_vitro/devtools/groovy-1.8.9/bin/groovy (found at GROOVY_HOME)
GroovyServ home directory: /cygdrive/c/in_vitro/devtools/groovyserv-0.11
GroovyServ work directory: /home/FengJing/.groovy/groovyserv
Original classpath: (none)
GroovyServ default classpath: /cygdrive/c/in_vitro/devtools/groovyserv-0.11/lib/*
Killed groovyserver of 224(1961)

簡単ですね。たったこれだけの手間で、Groovyスクリプトの実行が爆速になります。

"@GrabConfig(systemClassLoader=true)"を使う時の注意点

通常はgroovyclientによる実行のたびにクラスローダが生成されて"@Grab"で依存関係が読み込まれます。クラスのstaticフィールドなんかもそうですが、つまり、通常は実行のたびにクラスローダがリセットされると考えてよいでしょう。

ただし、当然groovyserver側でシステムクラスローダなどで読み込まれたクラスは残ります。

それで注意が必要なのが、"@GrabConfig(systemClassLoader=true)"を使う場合です。これを使うと、"@Grab"したのが(多分)groovyserver側のシステムクラスローダに読み込まれます。ということは、初回にロードされたものが以降もずっと残ることになります。

この挙動は、システムクラスローダで読み込まれたライブラリが設定ファイルを読み込むときに、初回に読み込まれた設定がずっと残り続け、設定ファイルを書き換えても反映されないという挙動につながります。slf4j + logbackでlogback.groovyを読み込む場合が該当したりしてます。

この場合は、groovyserverを再起動する他ありません。

$ groovyserver -r
Groovy home directory: /cygdrive/c/in_vitro/devtools/groovy-1.8.9
Groovy command path: /cygdrive/c/in_vitro/devtools/groovy-1.8.9/bin/groovy (found at GROOVY_HOME)
GroovyServ home directory: /cygdrive/c/in_vitro/devtools/groovyserv-0.11
GroovyServ work directory: /home/FengJing/.groovy/groovyserv
Original classpath: (none)
GroovyServ default classpath: /cygdrive/c/in_vitro/devtools/groovyserv-0.11/lib/*
Killed groovyserver of 6672(1961)
Restarting groovyserver
Starting....
groovyserver 7936(1961) is successfully started

"@Grab"使えるの?とか、クラスのstaticフィールドどうなるの?とかは、GroovyServのFAQページにあったりします:



プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2013-03-09 23:17:17
md5:84bd9dbcc8089e6b01d6a3d71e124267
sha1:ab0996fa0a0570fd8ba02783308637e37193db69