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

Grails v3.3.3+JSON Views 1.2.7深度渲染域对象栈溢出问题求助

解决Grails 3.3.3 + JSON Views 1.2.7深度渲染域对象的栈溢出问题

我之前碰到过一模一样的问题,这种栈溢出几乎都是双向关联的循环引用搞的鬼——哪怕你用了join fetch,JSON Views默认还是会递归渲染关联对象的反向引用(比如Site里的customer属性),无限循环下去直到栈爆掉。下面给你几个靠谱的解决方案:

1. 明确域类关联并控制JSON渲染范围

首先检查你的Site域类,确保双向关联的配置清晰,然后在JSON视图里显式指定要渲染的属性,避免递归:

修正域类配置

class Site {
    String name
    Customer customer
    // 明确所属关系,帮助GORM和JSON Views识别关联方向
    static belongsTo = [customer: Customer]
}

创建专属JSON视图模板

在grails-app/views/customer/_customer.gson创建模板,只渲染需要的属性,跳过反向引用:

model {
    Customer customer
}
json {
    id customer.id
    name customer.name
    // 手动处理sites关联,只渲染Site的基础属性,不碰customer字段
    sites customer.sites.collect { site ->
        [id: site.id, name: site.name]
    }
}

然后在控制器的index动作里调用这个模板:

def index() {
    // 保持你的join fetch查询
    def customers = Customer.findAll(fetch: [sites: 'join'])
    respond customers, view: 'index'
}

对应的index.gson视图可以这样写:

model {
    List<Customer> customerList
}
json customerList.collect { customer ->
    g.render(template: '/customer/customer', model: [customer: customer])
}

2. 用注解忽略反向引用

如果不想写模板,也可以直接在Site类里用@JsonIgnore标记反向引用,让JSON序列化时跳过它:

import com.fasterxml.jackson.annotation.JsonIgnore

class Site {
    String name
    @JsonIgnore // 忽略这个属性,避免循环渲染
    Customer customer
    static belongsTo = [customer: Customer]
}

这种方式更简洁,但缺点是全局生效,如果其他地方需要渲染Site的customer属性会受影响。

3. 用JSON Views的includes参数精准控制

你也可以在渲染时直接指定要包含的属性路径,不需要写模板:

def index() {
    def customers = Customer.findAll(fetch: [sites: 'join'])
    respond customers, [includes: ['id', 'name', 'sites.id', 'sites.name']]
}

这种方式适合简单场景,快速解决问题。

4. 检查Bootstrap数据是否有异常

最后确认一下Bootstrap里的数据初始化有没有问题,比如会不会不小心把同一个Site关联到多个Customer,或者出现其他意外的循环关联:

def init = { servletContext ->
    def cust1 = new Customer(name: 'Customer 1').save(flush: true, failOnError: true)
    def cust2 = new Customer(name: 'Customer 2').save(flush: true, failOnError: true)
    def site = new Site(name: 'Site A', customer: cust1).save(flush: true, failOnError: true)
    // 确保没有类似 site.customer = cust2 这种错误赋值
}

以上几种方法都能解决栈溢出问题,推荐第一种用模板的方式,因为它最灵活,能精准控制每个视图的输出内容。

内容的提问来源于stack exchange,提问作者WILLIAM WOODMAN

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 12:08:39