You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Grails JSON序列化异常:JSONWriter实例莫名变更引发JSONException

Grails 5.2.4 序列化ArrayList为JSON时触发JSONException的诡异问题

问题详情

在Grails 5.2.4项目(搭配Groovy 3.0.11、Java Eclipse Adoptium Temurin-11.0.18+10)里,把Form对象的ArrayList转成JSON响应时,直接抛出org.grails.web.json.JSONException,错误提示是预期KEY模式但当前为OBJECT模式。

调试时发现:

  • 在DomainClassMarshaller的marshalObject方法里,执行JSONWriter writer = json.getWriter()后,拿到的writer和json.writer根本不是同一个实例
  • json.writer的实例还会不停变,身份一直切换
  • 调用json.property写主键的时候,因为json.writer处在OBJECT模式,直接触发了异常
  • 已经设了字段修改断点和JSONWriter构造断点,但完全没触发

排查与解决思路

  • 先查Form类的序列化配置
    看看Form类是不是被误标成了Domain类(比如不小心加了@Entity或者Grails的Domain注解),导致被DomainClassMarshaller处理,而不是用普通对象的Marshaller。另外检查有没有给Form类自定义Marshaller,逻辑会不会有问题搞乱了writer状态。

  • 排查JSON上下文的冲突情况
    看看控制器里在序列化之前有没有手动操作过JSONWriter,比如之前的写入没正确关闭,导致后续的writer状态乱掉。还有全局JSON配置里有没有改默认Marshaller的优先级,会不会让DomainClassMarshaller错误处理了非Domain对象。

  • 手动指定Marshaller处理Form集合
    可以在控制器里直接指定用普通对象Marshaller来序列化Form的ArrayList,比如:

    // 手动注册Form的Marshaller
    JSON.registerObjectMarshaller(Form) { Form form ->
        [
            id: form.id,
            name: form.name
            // 按需添加其他需要序列化的字段
        ]
    }
    def responseJson = formArrayList as JSON
    render responseJson as JSON
    
  • 试试升级Grails小版本
    查下Grails 5.2.x后续的小版本有没有修复类似的Marshaller上下文问题,比如升级到5.2.5或者更高同系列版本测试下,说不定是版本本身的bug。

  • 调整调试断点
    别盯着构造断点了,试试在JSONWriter的setMode方法上设断点,跟踪模式切换的触发点——毕竟异常是模式不匹配导致的,这个断点应该更有用。另外打印json对象的完整堆栈,看看它是哪里创建的,有没有上下文复用的问题。

内容的提问来源于stack exchange,提问作者Pepijn Schmitz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 11:22:47