Groovy FastStringService RuntimeException

One of the systems I use at work is a Java-based SaaS platform. This platform makes itself extensible by allowing for custom scripting to be done on it via Groovy, a scripting language that runs on the JVM. This is a fairly common setup that I’ve seen on a variety of platforms over the years, and it works well enough… though editor support for Groovy is frequently… not great. Beyond that, the other pain point is that anyone wanting to leverage said scripting has to make sure they build things that are appropriate for the Groovy and Java versions the platform leverages. This can sometimes be annoying, though the platform I’m currently working with offers a fairly simple means by which I could check this by running the following in their debug environment:

import groovy.lang.GroovySystem
import java.lang.System

println("Groovy version: ${GroovySystem.version}")
println("Java version: ${System.getProperty('java.version')}")

This shows me:

This is relevant because for the years I’ve used this particular platform, it only offered Groovy 2. In a recent upgrade, Groovy 4 became a (highly welcome) option, and I’ve been working with moving some of my existing code to leverage Groovy 4. I quickly ran into an unexpected error in a relatively trivial script, though:

exception:java.lang.RuntimeException: Unable to load FastStringService

After a little debugging, I determined that using a JsonSlurper instance’s parseText method was the culprit. I could simplify the problematic code down to:

import groovy.json.JsonSlurper

String multiline = '''
{
  "host": "some-junk"
}
'''

JsonSlurper slurper = new JsonSlurper()
Map parsed = slurper.parseText(multiline) as Map
println(parsed)

My guess was some type of conflict between these particular point releases of Java 11 and Groovy 4. For example, I didn’t see the same behavior on my local machine with Groovy 4.0.21 and Java 11.0.14. After a bunch of digging where I found reports of people having this issue and then seeing it resolved with a new release, I found a fix in this support article.

According to the article, the issue is a dependency conflict, though nothing is elaborated beyond that. More importantly, though, it made me aware that Groovy 4 has a JsonSlurper class and a JsonSlurperClassic class that can prevent some of these issues. I updated my code to use that, and sure enough everything was happy again:

import groovy.json.JsonSlurperClassic

String multiline = '''
{
  "host": "some-junk"
}
'''

JsonSlurperClassic slurper = new JsonSlurperClassic()
Map parsed = slurper.parseText(multiline) as Map
println(parsed)

The JsonSlurperClassic class seems, sensibly, to have the exact same API as the JsonSlurper class, so updating my code is only a mild annoyance.