別のドメイン オブジェクトへの null 許容参照を持つ既存のドメイン オブジェクトに JSON ペイロードをバインドしようとすると、インバウンド JSON が参照に対して null を示している場合、バインドは失敗します。これにより、永続化の試行が次のエラーで失敗します。
| Error 2011-12-21 10:21:24,202 ["http-bio-8080"-exec-3] ERROR hibernate.AssertionFailure - an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session)
Message: null id in server.Uploader entry (don't flush the Session after an exception occurs)
Line | Method
->> 105 | update in server.SessionController
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 1110 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 603 | run . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^ 722 | run in java.lang.Thread
| Error 2011-12-21 10:21:24,206 ["http-bio-8080"-exec-3] ERROR errors.GrailsExceptionResolver - AssertionFailure occurred when processing request: [POST] /Server/session/2
null id in server.Uploader entry (don't flush the Session after an exception occurs). Stacktrace follows:
Message: null id in server.Uploader entry (don't flush the Session after an exception occurs)
Line | Method
->> 105 | update in server.SessionController
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 1110 | runWorker in java.util.concurrent.ThreadPoolExecutor
| 603 | run . . . in java.util.concurrent.ThreadPoolExecutor$Worker
^ 722 | run in java.lang.Thread
問題のドメイン オブジェクトは次のとおりです。
class Session {
DateTime dateCreated
DateTime lastUpdated
String ip
String state
static hasOne = [uploader:Uploader]
static constraints = {
ip blank: false
state blank: false
uploader nullable: true, unique: true
}
}
class Uploader {
DateTime dateCreated
DateTime lastUpdated
Session session
String firstName
String lastName
String organization
String phoneNumber
String emailAddress
static constraints = {
firstName blank: false
lastName blank: false
organization blank: false
}
}
エラーをスローするコントローラーコードは次のとおりです。
def update() {
def sessionInstance = Session.get(params.id)
if (!sessionInstance) {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'session.label', default: 'Session'), params.id])
redirect(action: "list")
return
}
if (params.version) {
def version = params.version.toLong()
if (sessionInstance.version > version) {
sessionInstance.errors.rejectValue("version", "default.optimistic.locking.failure",
[message(code: 'session.label', default: 'Session')] as Object[],
"Another user has updated this Session while you were editing")
render(view: "edit", model: [sessionInstance: sessionInstance])
return
}
}
sessionInstance.properties = params
if (!sessionInstance.save(flush: true)) { // <---- Error thrown here
render(view: "edit", model: [sessionInstance: sessionInstance])
return
}
flash.message = message(code: 'default.updated.message', args: [message(code: 'session.label', default: 'Session'), sessionInstance.id])
redirect(action: "show", id: sessionInstance.id)
}
これは、問題を引き起こす JSON ペイロードです。
{
"id":2,
"dateCreated":"2011-12-21T09:33:33-06:00",
"ip":"127.0.0.1",
"lastUpdated":"2011-12-21T09:33:33-06:00",
"state":"closed",
"uploader":null
}
しかし、この JSON ペイロードは問題なく動作します。
{
"class": "server.Session",
"id":2,
"dateCreated":"2011-12-21T09:33:33-06:00",
"ip":"127.0.0.1",
"lastUpdated":"2011-12-21T09:33:33-06:00",
"state":"closed",
"uploader":null
}
何が起こるかというとuploader
、セッションのプロパティが に設定されてい"server.Uploader : null"
ます。これは の後.dump()
のsessionInstance
オブジェクトsessionInstance.properties = params
です:
<server.Session@713c6968 dateCreated=2011-12-21T09:33:33.000-06:00 lastUpdated=2011-12-21T09:33:33.000-06:00 ip=127.0.0.1 state=closed errors=grails.validation.ValidationErrors: 0 errors id=2 version=1 uploader=server.Uploader : null>
プロパティが JSON ペイロードにある場合はすべて正常に機能し"class": "server.Session"
ますが、JSON ペイロードがないとすべてが機能しなくなります。データバインディングはこれを処理できると思います.残りのプロパティはうまくマッピングされていますが、参照にはひどく失敗しているようです.
最後に、これに遭遇した理由は、REST API に対して Griffon クライアントを構築しようとしているからです。HTTPBuilder は、元の JSON 応答を に変換するときに を取り除いているようです"class": "server.Session"
。net.sf.json.JSONObject
応答にはプロパティが含まれていますが、ダンプには含まれてnet.sf.json.JSONObject
おらず、後続の JSON 要求ペイロードも含まれていません。
- これは、JSON オブジェクトの「クラス」プロパティがない場合の Grails のデータ バインド方法のバグですか?
- これは、HTTPBuilder が JSON 応答を解析する方法のバグですか?
- HTTPBuilder が net.sf.json.JSONObject から JSON を出力する方法のバグですか?
- 私は完全に間違ったことをしているだけですか?
アップデート
私はいくつかの追加情報を見つけました:
- 一意の制約を削除しても動作は変わりません
uploader
フィールドがnullではなく、受信 JSON オブジェクトがそれを に設定しようとしている場合null
、プロパティは変更されません (エラーは発生しません)。ただし、"class": "server.Session"
プロパティが受信 JSON ペイロードにある場合はnull
、期待どおりに変更されます。