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
相关产品推荐
相关产品推荐

