Grails AppEngine PluginでJPAを使用する(失敗)
Grails AppEngine pluginでJPAを使用するには
前日、以下のページにてJPAを使用する場合には追加でプラグイン入れないといけないという記述を見つけたので、再度 Google App Engine 開発の手順を整理してみる。 Grails - Plugin: Grails AppEngine plugin
開発環境構築から、Grails App Engine Pluginインストールまでの流れ
以前投稿したとおり。
grails install-plugin app-engine
コマンドを実行した後は、 grails install-plugin gorm-jpa
コマンドを実行。
grails create-domain-class com.Book
で適当なドメインクラス作成後、 grails generate-all com.Book
でview、controller作成。
grails app-engine run
コマンドで動作確認。
book/list にアクセス
http://localhost:8080/
にアクセス。ちゃんと動作するようになった。http://localhost:8080/book/list
にアクセスすれば、ちゃんと本の一覧画面が表示される。http://localhost:8080/book/create
で新規登録画面へ。ただここで登録しようとするとエラーとなってしまう。
org.codehaus.groovy.runtime.InvokerInvocationException: java.lang.NullPointerException
at com.google.apphosting.utils.jetty.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:54)
at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
at com.google.apphosting.utils.jetty.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:54)
at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:306)
Caused by: java.lang.NullPointerException
at org.datanucleus.jpa.EntityManagerImpl.find(EntityManagerImpl.java:204)
at org.datanucleus.store.appengine.jpa.DatastoreEntityManager.find(DatastoreEntityManager.java:48)
at org.grails.jpa.JpaPluginSupport$__clinit__closure3_closure6_closure11_closure19.doCall(JpaPluginSupport.groovy:253)
at com.BookController$_closure3.doCall(BookController.groovy:18)
at com.BookController$_closure3.doCall(BookController.groovy)
... 4 more
プラグインの説明サイトを見ていると、 grails generate-all com.Book
にて作成したcontrollerでは正常に動作せず、手を加える必要があるようだ。
(例)
def jpaTemplate
def transactionTemplate
def save = {
transactionTemplate.execute({ status ->
def album = new Album(params)
if (!album.hasErrors() && album.validate()) {
jpaTemplate.persist(album)
jpaTemplate.flush()
flash.message = "Album ${albumInstance.id} created"
redirect(action: show, id: album.id)
} else {
status.setRollbackOnly()
render(view: 'create', model: [album: album])
}
} as TransactionCallback)
}
面倒くさい! ということで、夜にでも JDO で試してみたい。
JDO だと Gorm は使えないんだよね。でも generate-all コマンドで View や Controller を自動生成してくれるから一長一短か。
ディスカッション
コメント一覧
ゲンゾウさんこんにちは。
どんなドメインクラスを作りましたか?
https://svn.codehaus.org/grails-plugins/grails-gorm-jpa/trunk/grails-app/domain/org/acme/Person.groovy
をみると、JPAのアノテーションが必要みたいです。ただ、これをやってさらに
●nativeジェネレータの問題に関する例外が発生するのでidを以下のように定義する。
@Id
// @GeneratedValue (strategy = GenerationType.AUTO)
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id
とすることで、私はローカル開発サーバ
では動かせました。ただ、以下の問題がクリアできず
本番サーバでは動作させるまでには行きませんでした。
http://artofsystems.blogspot.com/2009/07/popstat-on-google-app-engine.html
http://code.google.com/p/googleappengine/issues/detail?id=1240#c5
>uehajさん
情報ありがとうございます。
どうやら以下のサイトからサンプルをコピーしたのですが、それに誤りがあったためのようです。
(ちゃんと確認していれば…)
Grails – Plugin: Grails AppEngine plugin [http://www.grails.org/plugin/app-engine]
def jpaTemplate
def transactionTemplate
def save = {
transactionTemplate.execute( { status ->
def album = new Album(params)
if(!album.hasErrors() && album.validate() ) {
jpaTemplate.persist(album)
jpaTemplate.flush()
flash.message = "Album ${albumInstance.id} created" // <<=ここがおかしい
redirect(action:show,id:album.id)
}
else {
status.setRollbackOnly()
render(view:'create',model:[album:album])
}
} as TransactionCallback ) }
ただし、新たな問題と奮闘中ですw