Groovy JsonBuilder触发StackOverflowError问题及版本升级咨询
关于Groovy 2.4.21中JsonBuilder栈溢出问题的解决方案确认
我们遇到了一个与GROOVY-8916类似的Bug,该问题出现在Groovy 2.4.21版本中,但2.4.12版本无此问题。
相关代码
import groovy.json.JsonBuilder void update(Map request, String env=null, String apiUrl=null, String credentialsId=null){ env = env ? env : getAthenaEnv() apiUrl = apiUrl ? apiUrl : (props.athena.apiUrl ?: props.athena[env].apiUrl) credentialsId = credentialsId ? credentialsId : (props.athena.credentialsId ?: props.athena[env].credentialsId) print "Updating athena record for ${request.appName} in ${env} environment" request = replaceNull(request) withCredentials([string(credentialsId: credentialsId, variable: 'apikey')]) { def requestData = new JsonBuilder(request).toString() def sanitizer = load "src/utils/SanitizerUtil.groovy" def projectName = sanitizer.sanitize(request.appName) def requestUrl = "${apiUrl}/applications/${projectName}" print "requestData: ${requestData}" def response = httpRequest url: requestUrl, customHeaders: [[name: 'apikey', value: apikey]], httpMode: 'PUT', contentType: 'APPLICATION_JSON', requestBody: requestData, validResponseCodes: '200,404' print "response.status: ${response.status}" } }
错误堆栈信息
[2023-05-09T22:03:55.095Z] java.lang.StackOverflowError [2023-05-09T22:03:55.095Z] at org.codehaus.groovy.util.AbstractConcurrentMap.getOrPut(AbstractConcurrentMap.java:37) [2023-05-09T22:03:55.095Z] at org.codehaus.groovy.reflection.GroovyClassValuePreJava7.get(GroovyClassValuePreJava7.java:96) [2023-05-09T22:03:55.095Z] at org.codehaus.groovy.reflection.ClassInfo.getClassInfo(ClassInfo.java:172) [2023-05-09T22:03:55.095Z] at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.getMetaClass(MetaClassRegistryImpl.java:281) [2023-05-09T22:03:55.095Z] at org.codehaus.groovy.runtime.InvokerHelper.getMetaClass(InvokerHelper.java:901) [2023-05-09T22:03:55.095Z] at org.codehaus.groovy.runtime.DefaultGroovyMethods.getMetaPropertyValues(DefaultGroovyMethods.java:450) [2023-05-09T22:03:55.095Z] at org.codehaus.groovy.runtime.DefaultGroovyMethods.getProperties(DefaultGroovyMethods.java:469) [2023-05-09T22:03:55.095Z] at groovy.json.JsonOutput.getObjectProperties(JsonOutput.java:338) [2023-05-09T22:03:55.095Z] at groovy.json.JsonOutput.writeObject(JsonOutput.java:331) [2023-05-09T22:03:55.095Z] at groovy.json.JsonOutput.writeMap(JsonOutput.java:469) [2023-05-09T22:03:55.095Z] at groovy.json.JsonOutput.writeObject(JsonOutput.java:332) [2023-05-09T22:03:55.095Z] at groovy.json.JsonOutput.writeMap(JsonOutput.java:469) [2023-05-09T22:03:55.095Z] at groovy.json.JsonOutput.writeObject(JsonOutput.java:332) [2023-05-09T22:03:55.095Z] at groovy.json.JsonOutput.writeMap(JsonOutput.java:469)
问题确认
是否需要根据该问题升级至Groovy 2.5版本并使用JsonGenerator替代JsonBuilder?
解决方案说明
是的,升级到Groovy 2.5+版本并切换到JsonGenerator是解决这个问题的推荐方案。
原因:
从堆栈信息可以明确看到,栈溢出是因为JsonOutput在序列化Map时陷入了无限递归循环——这正是GROOVY-8916中描述的问题:Groovy 2.4.x的JsonBuilder/JsonOutput会错误地遍历Groovy对象的元属性,导致递归调用无法终止。而Groovy 2.5版本彻底重构了JSON序列化模块,新增的JsonGenerator修复了这个递归遍历的Bug,同时提供了更灵活的配置来控制序列化行为。
临时替代方案(无法立即升级时):
如果暂时无法升级Groovy版本,可以通过以下方式规避问题:
- 将Groovy Map转换为纯Java HashMap,避免触发元属性遍历:
def requestData = new JsonBuilder(new HashMap(request)).toString()
- 手动指定需要序列化的属性列表,只处理业务相关字段,跳过动态生成的元属性。
内容的提问来源于stack exchange,提问作者Reid Watson
相关产品推荐
相关产品推荐

