Groovy and Java Strings

I am totally a newbie when it comes to Groovy, and when using it a bit of for our CI (Jenkins), I stumbled upon the non-intuitive difference between a Groovy and a Java String.

Some code

Just put some items in a Set, and look for it:

Set<String> s = new HashSet<String>();
def artifactId = "commons-lang3"
def version = "3.17.0"
def jarName = "${artifactId}-${version}.jar"
s.add(jarName)
println(s.contains("commons-lang3-3.17.0.jar")) // false

I first thought it was some white space problems, so I tried to trim() the string… and it worked! But there was no white space.

Set<String> s = new HashSet<String>();
def artifactId = "commons-lang3"
def version = "3.17.0"
def jarName = "${artifactId}-${version}.jar"
s.add(jarName.trim())
println(s.contains("commons-lang3-3.17.0.jar")) // true

Not the same String

A Groovy String is not a Java string, that’s all…:

def jarName1 = "${artifactId}-${version}.jar"
def jarName2 = artifactId + "-" + version + ".jar"
println(jarName2.equals(jarName1)) // false
println(jarName1.equals(jarName2.trim())) // false
println(jarName2.equals(jarName1.trim())) // true
println(jarName1.getClass().getSimpleName()) // GStringImpl
println(jarName2.getClass().getSimpleName()) // String
println(jarName1.toString()) // String

So depending on the type of string used in a Set or a Map, it may find them or not depending on which version is used.
What I find worse, is that calling trim() on a GString actually returns a Java String and not a GString.

Conclusion

Read the documentation…
Despite the behavior being documented on the Groovy website, I find it totally unintuitive, and very prone to subtle bugs…
I hate Groovy.