0

当我尝试将 JSON 有效负载绑定到对另一个域对象具有可为空引用的现有域对象时,如果入站 JSON 指示引用为空,则绑定失败。这会导致持久性尝试失败并出现以下错误:

| 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>

"class": "server.Session"属性在 JSON 有效负载中时,一切都正常工作,但没有它,一切都会崩溃。我认为数据绑定能够处理这个问题,因为它可以很好地映射其余属性,但似乎只是因为参考而失败了。

最后,我遇到此问题的原因是因为我正在尝试针对 REST API 构建 Griffon 客户端,并且似乎 HTTPBuilder在"class": "server.Session"将原始 JSON 响应转换为时剥离了net.sf.json.JSONObjectresponse 中有属性,但转储net.sf.json.JSONObject没有,后续的 JSON 请求有效负载也没有。

  1. 当 JSON 对象没有“类”属性时,这是 Grails 数据绑定方式的错误吗?
  2. 这是 HTTPBuilder 如何解析 JSON 响应的错误吗?
  3. HTTPBuilder 如何从 net.sf.json.JSONObject 输出 JSON 是否存在错误?
  4. 我只是在做完全错误的事情吗?

更新

我发现了一些额外的信息:

  1. 删除唯一约束不会改变行为
  2. 如果该uploader字段为非 null并且入站 JSON 对象尝试将其设置为null,则该属性不会更改(并且不会发生错误)。但是,如果该"class": "server.Session"属性在入站 JSON 有效负载中,它会null按预期更改。
4

1 回答 1

0

IIRC Json-lib 的 JSONObject 将自动去除“类”和“元类”等特殊属性(在 POGO 的情况下)。您可以通过 JsonConfig 实例配置此行为,但是我不知道 HTTPBuilder 是否允许您在适当的时间注入此类实例。

另一种选择(有点hacky)是以Json-lib不会剥离的不同名称(比如clazz)发送类属性值。您必须在 Grails 端注册一个过滤器才能将“clazz”映射到“class”。

于 2011-12-21T18:12:52.113 回答