Hatena::ブログ(Diary)

ushidayの日記 RSSフィード

2009-11-07

TextMateの設定

| 23:06

以前、トライアル版で入れていた”TextMate”を久々に開いたら、とっくの昔に期限が切れていて、「登録しますか?」を聞かれるので、購入しました。で折角なんで、G*な感じで、ちゃんと使う様に設定したので、メモを...。

TextMateの日本語表示と入力の設定

TextMateデフォで、日本語表示と入力に対応してないので、まず日本語入力/表示の設定をします。

ここまでで、日本語の入力は出来るのですが、日本語の横幅の問題から重なって表示されます。

f:id:ushiday:20091107193403p:image

フォントの幅が狭くて、若干違和感がありますが、これで日本語が使えます。

f:id:ushiday:20091107195424p:image

f:id:ushiday:20091107195423p:image

次に、TextMate用の"Groovy,GSP"シンタックスハイライトや各種スニペット、コマンドなどを設定します。

GroovyのBundle

試しに”Groovy Console”を実行したら、”ユニバーサルアクセス”設定の”補助装置にアクセス出来るようにする”を許可していないといけない様なので、チェックをいれます。

f:id:ushiday:20091107201939p:image

f:id:ushiday:20091107201934p:image

f:id:ushiday:20091107201932p:image

GrailsのBundle

f:id:ushiday:20091107212031p:image


Win版の”E Text Editor”もあるので、また今度、会社のWin環境で、そちらも試してみたいです。

ブログは、ごぶさたな感じなのですが、IlE-RPGWebサービス化とか、早いとこブログにしとかないと、こりゃ忘れそうだ。

2009-07-15

IBM iのGrails Plugin その2

| 17:20

IBM i(AS/400)Grails Plugin「Systemi Grails Domain Plugin 」の続きです。

grails generate-systemi-all

grails generate-systemi-all」コマンドは、DomainClassから、静的scaffoldでcontrollerとviewを作成します。

前回moも書きましたが、DomainClassを作成する際に、うっかり小文字のドメインを作成して、このgenerateコマンドでこけてしまいました。

C:\SAVF\grails\1.1.1\cscfle>grails generate-systemi-all Employee
Welcome to Grails 1.1.1 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: C:\Program Files\grails\grails-1.1.1

Base Directory: C:\SAVF\grails\1.1.1\cscfle
Running script C:\Documents and Settings\ushida\.grails\1.1.1\projects\cscfle\plugins\systemitools-0.4\scripts\Generate
ystemiAll.groovy
Environment set to development
Warning, target causing name overwriting of name default
  [groovyc] Compiling 2 source files to C:\Documents and Settings\ushida\.grails\1.1.1\projects\cscfle\classes
name: Employee
  [groovyc] Compiling 1 source file to C:\Documents and Settings\ushida\.grails\1.1.1\projects\cscfle\classes
domainClass.name Employee
domainObject:<Employee@3b84ee id=0 sha002=null sha003=null sha004=0 sha005=null sha006=null sha007=0 sha008=0 sha009=nu
l sha900=0 sha901=0 sha902=0 sha903=0 newEntity=false version=null>
domainObject.COMPOSITE_KEY:false
propertyName: employee
Generating views for domain class Employee ...
Finished generation for domain class Employee
Finished generation of EmployeeController.groovy and associated views

grails run-app」で確認します。

f:id:ushiday:20090715171701p:image

  • こうなりました

f:id:ushiday:20090715171700p:image

IBM iのGrails Plugin その1

| 16:33

IBM i(AS/400)のプラグインGrailsの公式サイトで調べると、意外なことに3つも存在してます。GrailsとASの両方をやってる人がいて、さらにPluginまで作っている人がいると思うと、世界は広いなと思います。もし自分に英語力があったらコミュニケーションとってみたいです。

Grailsプラグイン

ibm iのカテゴリー

  • IBM i support
  • Systemi Grails Domain Plugin
  • jtopen

その中で、「Systemi Grails Domain Plugin 」の”既存DBリバースエンジニアリング”が直ぐ目に付いたので、早速試してみました。本来ドメインありきのGrailsにとって、RDBありきではないので本筋とは違うカモですが、RDBドメインに置き換えるとしても、”エイ!ヤー!”でフィールド(カラム)を引き込んでくれるだけでも、結構ありがたい気がします。

導入手順等はこちらを参考にさせて頂きました。

インストール
  1. 適当なアプリケーションを「grails create-app」で作成&カレントディレクトリ移動。
  2. grails install-plugin http://grails400utils.googlecode.com/files/grails-systemitools-0.4.zip
  3. 追加されたコマンド
  4. grails compile」を実行
build-systemi-grails-domain

「build-systemi-grails-domain」は、AS/400内にある既存DB2データベースから、DomainClassにリバースエンジニアリングするコマンドです。コマンドを実行するとインタラクティブに”ホストのアドレス(IP等)”、”ASユーザー名”、”ユーザーパスワード”、”ライブラリー”、”ファイル名”、”DomainClass名”の順に要求されます。

(※実はこのDomainClass名の指定ですが、つい”create-domain-class”コマンドの癖で、先頭を小文字にしてしまいましたが、この後に出てくるgenerateコマンドのscaffoldで見事にコケました。忘れないようにDomainClass名の先頭を大文字にします。

しかし、コマンドを実行すると「Error executing script BuildSystemiGrailsDomain:〜」とエラーになってしまいました。その場合は「grails cleanをしてみて」という説明っぽいので、とりあえずcleanをしてみます。自分の場合は、cleanした後は、問題なく動きました。

grails build-systemi-grails-domain
------ 中略 ------
Please enter IP:
192.168.x.xxx
user:
USHIDA5035
password:
*******
library:
CSCFLE
file:
SHAMASF
Grails domain class name:
Employee
------ 中略 ------
     [move] Moving 7 files to C:\SAVF\grails\1.1.1\cscfle\src\templates\scaffolding
     [move] Moving 1 file to C:\SAVF\grails\1.1.1\cscfle\grails-app\taglib
     [echo]  be sure to modify grails-app/conf/DataSource.groovy to specify your System i settings eg:
     [echo]     dataSource {
     [echo]         pooled = true
     [echo]         url = "jdbc:as400://192.168.x.xxx/CSCFLE"
     [echo]         driverClassName = "com.ibm.as400.access.AS400JDBCDriver"
     [echo]         username = "USHIDA5035"
     [echo]         password = "*******"
     [echo]         dialect = org.hibernate.dialect.DB2400Dialect.class
     [echo]     }
Finished generation of domain

[echo]で表示されている様に、「$PROJECT_HOME/grails-app/conf/DataSource.groovy」を、以下の様に変更します。

dataSource {
    pooled = true
    url = "jdbc:as400://192.168.x.xxx/CSCFLE"
    driverClassName = "com.ibm.as400.access.AS400JDBCDriver"
    username = "USHIDA5035"
    password = "*******"
    dialect = org.hibernate.dialect.DB2400Dialect.class
}
environments {
	development {
	    dataSource {
	        dbCreate = "create-drop" // one of 'create', 'create-drop','update'
	    	url = "jdbc:as400://192.168.x.xxx/CSCDEV"    
	        loggingSql = true
	    }
	}
	test {
	    dataSource {
	        dbCreate = "update"
	    	url = "jdbc:as400://192.168.x.xxx/CSCTEST"    
            loggingSql = true
	    }
	}
	production {
	    dataSource {
	        //dbCreate = "update"
	    	url = "jdbc:as400://192.168.x.xxx/CSCFLE"    
	    }
	}
}

このようなDDS(Data Define Structure)から

(S:ゾーン10進、A:SBCS文字列、O:DBCS混合文字列、K:キー)

     A*****************************************************************
     A*   SHAMASF  社員マスター             04/08/20  CSC)Y.U     *
     A*****************************************************************
     A                                      UNIQUE
     A          R SHA00FR                   TEXT('社員マスター')
     A            SHA001         3S 0       COLHDG('社員コード')
     A*
     A            SHA002        16A         COLHDG('社員フリガナ')
     A            SHA003        16O         COLHDG('社員名')
     A            SHA004         8S 0       COLHDG('入社年月日')
     A            SHA005         1A         COLHDG('職務コード')
     A            SHA006        30O         COLHDG('項目')
     A            SHA007         3S 0       COLHDG('レベル係数')
     A            SHA008         7S 0       COLHDG('ダミー')
     A            SHA009         1A         COLHDG('削除フラグ')
     A*                                              D:削除
     A            SHA900         8S 0       COLHDG('作成日')
     A            SHA901         6S 0       COLHDG('作成時間')
     A            SHA902         8S 0       COLHDG('変更日')
     A            SHA903         6S 0       COLHDG('変更時間')
     A*KEY
     A          K SHA001                                              

このようなDomainClass(Employee.groovy)がリバースエンジニアリングされました。

class Employee implements Serializable {
	int id
	String sha002
	String sha003
	int sha004
	String sha005
	String sha006
	int sha007
	int sha008
	String sha009
	int sha900
	int sha901
	int sha902
	int sha903
	static constraints = {
		sha002(maxSize:16,nullable:false)
		sha003(maxSize:16,nullable:false)
		sha004(max:99999999,nullable:false)
		sha005(maxSize:1,nullable:false)
		sha006(maxSize:30,nullable:false)
		sha007(max:999,nullable:false)
		sha008(max:9999999,nullable:false)
		sha009(maxSize:1,nullable:false)
		sha900(max:99999999,nullable:false)
		sha901(max:999999,nullable:false)
		sha902(max:99999999,nullable:false)
		sha903(max:999999,nullable:false)
	}
	static final boolean ASSIGNED_KEY = true
	static final boolean COMPOSITE_KEY  = false
	static mapping = {
		table ('SHAMASF')
		version (false)
		id (generator:'assigned')
		columns {
			id (column:'SHA001',type:'int')
			sha002 (column:'SHA002', type:'string')
			sha003 (column:'SHA003', type:'string')
			sha004 (column:'SHA004', type:'int')
			sha005 (column:'SHA005', type:'string')
			sha006 (column:'SHA006', type:'string')
			sha007 (column:'SHA007', type:'int')
			sha008 (column:'SHA008', type:'int')
			sha009 (column:'SHA009', type:'string')
			sha900 (column:'SHA900', type:'int')
			sha901 (column:'SHA901', type:'int')
			sha902 (column:'SHA902', type:'int')
			sha903 (column:'SHA903', type:'int')
		}
	}
	boolean newEntity = false
	static transients = ['sha001', 'newEntity']
	def getSha001() {
		if (id) return id
		return 0
	}
	void setSha001 (def vlu) { id = vlu }
}

自分は、DomainClassの”mapping”とかよく解ってなかったのですが、こうやって結果で見ると非常に解り易いです。複合キーのファイルをリバースエンジニアリングすると「COMPOSITE_KEY=true」になって、idメソッドが「id (composite:['column1','column2'])」とリスト形式になっていました。

AS/400のファイルのキーが単一の整数フィールドだと、idとフィールドが2つにならないように、SetterとGetterがオーバーライドされているのにも感心しました。

grails generate-systemi-all」コマンドで静的scaffoldが出来るのですが、長くなってしまったので、次の日記に分けます。

IBM iにGrails1.1.1を入れる

| 15:11

IBM i(AS/400)に、最新のGrails1.1.1を入れてみた。

インストールは、

  1. 公式サイトtar.gzバイナリをDownloadして
  2. 解凍して
  3. 配置して
  4. 環境変数設定して
  5. $GRAILS_HOME/bin/startGrailsの修正(こちら参照)

するだけです。

とりあえず「create-app」と「create-domain-class」はOK。でも「generate-all」で下のエラーが出ちまいました。PluginMnager、GroovyPagesGrailsPluginあたりがうまくいってない?1.0系は問題なく動いたんですが...orz

org.codehaus.groovy.grails.exceptions.NewInstanceCreationException: Could not
 create a new instance of class [org.codehaus.groovy.grails.plugins.web.Groov
yPagesGrailsPlugin]!                                                         
        at java.lang.Exception.<init>(Exception.java:59)                     
        at java.lang.RuntimeException.<init>(RuntimeException.java:61)       
        at _PluginDependencies_groovy$_run_closure6_closure53.doCall(_PluginD
ependencies_groovy:449)                                                      
        at _PluginDependencies_groovy$_run_closure6_closure53.doCall(_PluginD
ependencies_groovy:0)                                                        
        at _GrailsSettings_groovy$_run_closure10.doCall(_GrailsSettings_groov
y:274)                                                                       
        at _GrailsSettings_groovy$_run_closure10.call(_GrailsSettings_groovy:
0)                                                                           
        at _PluginDependencies_groovy$_run_closure6.doCall(_PluginDependencie
s_groovy:447)                                                                
        at _GrailsPackage_groovy$_run_closure2.doCall(_GrailsPackage_groovy:1
28)                                                                          
        at GenerateAll$_run_closure1.doCall(GenerateAll.groovy:32)           
        at gant.Gant$_dispatch_closure4.doCall(Gant.groovy:324)              
        at gant.Gant$_dispatch_closure6.doCall(Gant.groovy:334)              
        at gant.Gant$_dispatch_closure6.doCall(Gant.groovy:0)                
        at gant.Gant.withBuildListeners(Gant.groovy:344)                     
        at gant.Gant.this$2$withBuildListeners(Gant.groovy:0)                
        at gant.Gant$this$2$withBuildListeners.callCurrent(Unknown Source)   
        at gant.Gant.dispatch(Gant.groovy:334)                               
        at gant.Gant.this$2$dispatch(Gant.groovy:0)                          
        at gant.Gant.invokeMethod(Gant.groovy:0)                             
        at gant.Gant.processTargets(Gant.groovy:495)                         
        at gant.Gant.processTargets(Gant.groovy:480)                         
Caused by: java.lang.ExceptionInInitializerError                             
        at java.lang.Throwable.<init>(Throwable.java:181)                    
        at java.lang.Error.<init>(Error.java:37)                             
        at java.lang.ExceptionInInitializerError.<init>(ExceptionInInitialize
rError.java:61)                                                              
        at java.lang.Class.forName(Class.java:189)                           
        ... 18 more                                                          
Caused by: java.lang.ClassCastException                                      
        at java.lang.Throwable.<init>(Throwable.java:181)                    
        at java.lang.Exception.<init>(Exception.java:29)                     
        at java.lang.RuntimeException.<init>(RuntimeException.java:32)       
        at java.lang.ClassCastException.<init>(ClassCastException.java:29)   
        at java.lang.String.compareTo2(String.java:1757)                     
        at java.util.Arrays.mergeSort(Arrays.java:1284)                      
        at java.util.Arrays.mergeSort(Arrays.java:1295)                      
        at java.util.Arrays.mergeSort(Arrays.java:1295)                      
        at java.util.Arrays.mergeSort(Arrays.java:1295)                      
        at java.util.Arrays.mergeSort(Arrays.java:1295)                      
        at java.util.Arrays.mergeSort(Arrays.java:1295)                      
        at java.util.Arrays.mergeSort(Arrays.java:1295)                      
        at java.util.Arrays.sort(Arrays.java:1223)                           
        at java.util.Collections.sort(Collections.java:159)                  
        ... 19 more                                                          
Error loading plugin manager: Could not create a new instance of class [org.c
odehaus.groovy.grails.plugins.web.GroovyPagesGrailsPlugin]!                  
$                                                                                                                                                         

少し調べてみましたが、自分の力では、解りませんでした。もう少し時間有ったらまた挑戦してみます。

2009-06-29

アーティファクトの勉強メモ

| 19:26

Grails徹底入門11章の続きを勉強しております。後半は、アーティファクトの勉強です。

先の章で、作成した「E-mail作成プラグイン」をアーティファクト化する内容です。

一通り読んでみましたが、E-mailぐらいの機能だとアーティファクトにする、メリットが正直ピンとこないです。プラグイン定義ファイルのdoWithSpringとdoWithDynamicメソッドで、出来た機能でも十分な気がしてしまいます。本当はもっと深い、アーティファクトの利用方法があると思うのですが、自分の発想ではとりあえず、思い浮かぶわけもなく、定義の仕方、使い方だけでもとりあえず勉強です。

ただ、アーティファクトにすることによって、groovyクラスに出来て、DSLでプロパティを定義できたり、アーティファクト作成コマンドが使えたりする事で、プラグインの裏だけでやっていた事が、Grailsの表面に表れた気が?します。そんなアーティファクトの勉強中に、少し引っかかったので、忘れないようにメモです。

プラグイン定義ファイル(〜GrailsPlugin.groovy)でアーティファクトのリロードイベント(onChangeクロージャ)を勉強していると、以下のような記述が出てきました。

------ 省略(〜GrailsPlugin.groovy) -------
def onChange = { event ->

if (application.isArtefactOfType(EmailArtefactHandler.TYPE,event.source)){

	def em = application.addArtefact(EmailArtefactHandler.TYPE,event.source)
	def beans = beans{
		// ビーンの内容を再度設定
		"send${em.shortName}"(org.springframework.mail.SimpleMailMessage){ bean ->
		bean.parent = ref("abstractMailMessage")
		if (em.getPropertyValue("subject")) subject = em.getPropertyValue("subject")
		if (em.getPropertyValue("from")) from = em.getPropertyValue("from")
		if (em.getPropertyValue("to")) to = em.getPropertyValue("to")
		if (em.getPropertyValue("cc")) cc = em.getPropertyValue("cc")
		if (em.getPropertyValue("bcc")) bcc = em.getPropertyValue("bcc")
		if (em.getPropertyValue("replyTo")) replyTo = em.getPropertyValue("replyTo")
		if (em.getPropertyValue("sentDate")) sentDate = em.getPropertyValue("sentDate")
		}
	}

	// クラスの確認
	println beans.class		// grails.spring.BeanBuilder

	// コンテキストにビーンを再登録
	if (event.ctx){
		beans.registerBeans(event.ctx)
	}

}

}
  • 疑問1:「"def beans"で定義した変数が、その後、beans.registerBeansメソッドが使えているのは何故?」
  • 疑問2:「そもそも"def beans="の後の突然現れた、”beans”メソッドは、クロージャーを引数にしてビーンを再定義しているのは、解るけど何処から発生しているの?」

この悩みがスッキリせずに、前に進むのはどうも躊躇いがあり、調べてみました。今までも”application”プロパティなどが、定義せず使えた事と同じなのだろうけど、実態がやっぱり気になります。

で結局、ソースを調べてみると、「org.codehaus.groovy.grails.plugins.DefaultGrailsPlugin」で”beans”メソッドの定義はされていて、戻り値は”grails.spring.BeanBuilder”でした。

------ 省略(DefaultGrailsPlugin.java) -------
public BeanBuilder beans(Closure closure) {
    BeanBuilder bb = new BeanBuilder(getParentCtx(), new GroovyClassLoader(application.getClassLoader()));
    bb.invokeMethod("beans", new Object[]{closure});
    return bb;
}

ついでにソースを覗いていると「doWith〜」とか、「get〜(プラグイン情報)」があったり、コンストラクタの引数に”pluginClass”が渡されて、「evaluate〜」で、プロパティを設定してたりしてそうな...そんな感じでした。

「DefaultGrailsPlugin」が、基盤となってプラグイン定義ファイルが動いてそうなのが、何となく解ったような気がしました。「DefaultGrailsPlugin」の方が実態で、「〜GrailsPlugin.groovy」は、まさに定義ファイルという事なのかな?コードリーディングをすると、こういう部分が理解されてパワーになるんだろうなぁ。

2009-06-24

9章、10章が終わった

| 11:38

ようやく、Grails徹底入門の9章と10章が終わりました。ちゃんと理解しているかどうかは、怪しいですけど、とにかく終わりました。最近余り、時間が取れなくて、進むペースがイマイチです。

内容的には、プラグインに関する事だったのですが、「Grailsの凄さは、プラグインにあるんだろうなぁ」と素人的に、垣間見たそんな内容でした。何となくですが、以前「9〜11章をぜひ先に読んで」って言われたのが、解った気がします。以下は、終わってみての感想ですが、何せ素人なので間違った表現が多いと思いますが、ご勘弁を。

grails.spring.BeanBuilder”は、XMLファイルでなく、GroovyのDSL?(この表現は不安です)で、ビーン定義出来てしまう事。これは、自分みたいな人間には、直感的で解り易いです。BeanBuilderを使っていて、特に意識はしないですが、クロージャーを引数にして、XMLと最終的に同等にしてくれているんだろうなぁ。便利だなぁと思いました。

自分は、”Spring”その物を使った経験が無いので、比較してどうだ?という思いは無いですが、”BeanBuilder”解りやすくて、いいんでない。と思いました。

”doWithSpring”は、プラグイン定義ファイル(〜GrailsPlugin.groovy)上に存在するクロージャですが、”BeanBuilder”をさらに意識せず使えて、ナイスな感じがしました。”doWithSpring”で、ビーンを定義するだけで、ApplicationContext上にロードされて、簡単にコントローラなどに、インジェクション出来てしまいます。

例えばこんな感じです。

    def doWithSpring = {
        // TODO Implement runtime spring config (optional)
    	//メール送信用ビーン定義(p348)
    	mailSender(org.springframework.mail.javamail.JavaMailSenderImpl){
    		host = "smtp.xxxxx.xxxxx"	//smtpサーバー
    		port = 587			//サーバーポート
    	}
    	//メールメッセージ用ビーン定義(p348)
    	simpleMailMessage(org.springframework.mail.SimpleMailMessage){
    		from = "xxxxx@xxxxxxx.com"	//送信元
    	}
    }

”doWithDynamicMethod”は、プラグイン定義ファイル上に存在するクロージャで、動的にメソッドを、コントローラなどのArtefactに追加できます。”doWithSpring”でロードしたビーンはコントローラで、簡単にインジェクションする事が可能です。

例えばこんな感じ

---------コントローラ----------
import org.springframework.mail.SimpleMailMessage
class HomeController {
	//ビーンのインジェクション
	def mailSender 
	def simpleMailMessage
	
	//メールテストアクション(p349)
	def simpletest = {
		
	def message = new SimpleMailMessage(simpleMailMessage)
	message.to = ["xxxxxx@xxxxxxxx.co.jp"]
	message.subject = "メール送信テスト"
	message.text = "メッセージ"
	try{
		//メール送信
		mailSender.send(message)
		render (text:"メールを送信しました")
	}catch(Exception e){
		e.printStackTrace()
		render (text:"送信エラー。スタックを調べて下さい。")
	}

	}

}

しかし、コントローラ共通の機能だったら、毎回ビーンをインジェクションしたり、関連するライブラリをインポートしたり、するのは手間なんで、そんな時”doWithDynamicMethod”で、以下の様に、動的に共通機能を実装できてしまいます。

---------プラグイン定義ファイル----------	                                      
def doWithDynamicMethods = { ctx ->
    //コントローラの参照
    application.controllerClasses.each{ controllerClass ->
    	// metaClass参照
    	def mc = controllerClass.metaClass
    	registerControllerProps(mc,ctx)
    }
}

//メール送信の実装
def registerControllerProps(mc,ctx){
		
	// sendEmailメッソドの追加
	mc.sendEmail = {params ->

	// SimpleMailMessageのコンストラクタに
	// コンテキストから取得したsimpleMailMessageビーンをセット
	def message = new org.springframework.mail.SimpleMailMessage(ctx.simpleMailMessage)
	if(params.from) message.from = params.from
	message.to = params.to
	message.subject = params.subject
	message.text = params.text
	try{
	// ビーンmailSenderをコンテキストから参照
	def sender = ctx.mailSender
	if(params.encoding) sender.defaultEncoding=params.encoding
	sender.send(message)
	}catch(Exception e){
	e.printStackTrace()
	}finally{
	return ""
	}

	}
	
}

---------コントローラ----------
class HomeController {
	
	def mailtest= {
		def message = "メッセージ"
		//メール送信(〜GrailsPlugin.groovyのdoWithDynamicMethodで実装)
		sendEmail(
			to:["xxxxxxx@xxxxxxxxx.co.jp"]
			,subject:"sendEmailのテスト"
			,text:message
			,encoding:"iso-2022-jp")
		
		render(text:"メールを送信しました sendEmail")
	}

}

上記とは別に、動的に追加した、メソッドにはリロード処理が必要になってきます。

これらプラグインのパワーを、早く使いこなせる様になりたいです。

2009-06-11

SpringBeanBuilderのお勉強で...その2

| 13:13

g*workshop第3回に行って来ました。

zkプラグインのお話や、今ホットな話題のGAE/Jのお話など盛りだくさんでした。

早くその話題にスムーズについていけるように、ならなきゃだけど、いつの日やら...orz

さて本題で、只今、Grails徹底入門のプラグイン10章を勉強中です。

doWithSpringクロージャーのお話から、"Spring BeanBuiler"を単独で動かすとう内容に移り、そもそもSpring Frameworkを知らない、自分の理解が全くもって悪いので、メモしときます。

Spring Beanbuilderでビーンを参照する際に、”プロパティ=ref("参照ビーンID",true)”の様に、第二引数に”true”を入れると、「親のApplicationContext内のみを参照」との事、以下の様なテスト用のビーンを2つ用意します。

  • BeanA
class BeanA{
	String name 
}
  • BeanB
class BeanB{
	String name 
	BeanA parent
}

groovyスクリプトで、以下のように、"true"を付けずに、Spring BeanBuilderを使っても、出来てしまったので、”true”は何のために有るのだろ?みたいなお馬鹿な事を思ってしまったのです。今思えば、ちゃんと本の文章を読めって事なんですが...o(x_x=。

  • SpringBuilderWithParent
import org.springframework.context.ApplicationContext
import grails.spring.BeanBuilder

// 親の生成
def builder = new BeanBuilder()
builder.beans{
	beanA(BeanA){
		name = "BeanA Parent"
	}
}
//子の生成
def builder2 = new BeanBuilder(builder.createApplicationContext())
builder2.beans{
	beanB(BeanB){
		name = "BeanB Chiled1"
		parent = ref("beanA")     //親のビーン参照
	}
}

def ctx = builder2.createApplicationContext()
assert ctx.beanB.parent.name == "BeanA Parent"

お馬鹿な頭で悩むこと数分、”親のみ”という言葉を思い出して、子自身の”ApplicationContext”に、同名のビーン定義が、あった場合でも、子の参照を回避して親から参照出来るという事?...。聞く相手もいないので、やってみました。

import org.springframework.context.ApplicationContext
import grails.spring.BeanBuilder

// 親の生成
def builder = new BeanBuilder()
builder.beans{
	beanA(BeanA){
		name = "BeanA Parent"
	}
}
//子の生成
def builder2 = new BeanBuilder(builder.createApplicationContext())
builder2.beans{
	beanA(BeanA){
		name = "BeanA Chiled"
	}

	beanB(BeanB){
		name = "BeanB Chiled1"
		parent = ref("beanA",true)     //親のビーン参照
	}
}

def ctx = builder2.createApplicationContext()
assert ctx.beanB.parent.name == "BeanA Parent"

”true”が無いと...

//------------------- 省 略 -------------------------------------
	beanB(BeanB){
		name = "BeanB Chiled1"
		parent = ref("beanA")     //子のビーン参照
	}
}
def ctx = builder2.createApplicationContext()
assert ctx.beanB.parent.name == "BeanA Chiled"

なるほど、動きは理解をしたけど、こういった機能を理解した上で、どんな場面で使えるかが重要なんでしょうね。

ちなみに同一IDのビーンを1つのbuilderの中で、複数回定義したら、エラーにはならず、最後に定義したビーンを参照しました。

//------------------- 省 略 -------------------------------------
def builder2 = new BeanBuilder(builder.createApplicationContext())
builder2.beans{

	beanA(BeanA){
		name = "BeanA Chiled1"
	}
        //同名ビーン
	beanA(BeanA){
		name = "BeanA Chiled2"
	}

	beanB(BeanB){
		name = "BeanB Chiled1"
		parent = ref("beanA")     //ビーン参照
	}
}
def ctx = builder2.createApplicationContext()
assert ctx.beanB.parent.name == "BeanA Chiled2"


”true”をつけた場合に、親のApplicationContextに指定されたビーンIDがなければ、子のApplicationContextに同名があってもちゃんとエラーになりました。あたりまえですね。

でも、一人でやってると、こういう理解で正しいのかが、心配(゚Д゚;)です。