Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Groovy Gotcha: String interpolation does not always execute, e.g. in `<list>.contains()`

Answer: it has to do with GString type and "lazy evaluation."

See http://docs.groovy-lang.org/latest/html/documentation/index.html#_string_interpolation for the formal documentation.

See https://blog.mrhaki.com/2009/08/groovy-goodness-string-strings-strings.html for someone's write-up on this.

Firm solution in the code below as commenter said is to explicitly cast it on creation using String targ = "${TARGET_DATA}"


I'm seeing what seems on the surface to be a delayed string interpolation or something in Groovy. I've figured out workarounds for my immediate needs, but the behaviour is a real gotcha, and a potential source for serious bugs...

I strongly suspect it arises from Groovy being a meta-language for Java, and some objects not using the usual string-matching routines.

This was discovered when we were trying to use a string interpolation on some parameter in Jenkins, and checking it against a list of pre-approved values - hence the resulting example below.

Consider this code:

TARGET_DATA= "hello"
data = ["hello"]
targ = "${TARGET_DATA}"

// Case 1: Check for basic interpolated string

if( data.contains(targ) ) {
  println "Contained interpolated string"
} else {
  println "Interpolation failed"
}

// Case 2: Check to see if using something that actively forces its interpolation changes the variable

println "interpolating targ = ${targ}"

if( data.contains(targ) ) {
  println "Contained re-interpolated string"
} else {
  println "re-Interpolation failed"
}

// Case 3: Use direct variable assignment

targ = TARGET_DATA

if( data.contains(targ) ) {
  println "Contained assigned variable"
} else {
  println "Assignment failed"
}

Its output is this:

Interpolation failed
interpolating targ = message: hello
re-Interpolation failed
Contained assigned variable

This indicates that:

  • In case 1 , the placeholder string is checked for in the list, and fails, as it hasn't been interpolated
  • In case 2, after forcing the interpreter to perform an interpolation against targ, the content of that variable isn't updated. At this stage, targ still contains a literal placeholder string
  • In case 3, after assigning the initial variable directly to the target variable, we get a successful match

My guess is that targ literally contains a string starting with a dollar sign, curly brace, and a variable name, etc. This only resolves under certain conditions, like the use of a println , but not in the case of a <list>.contains() which just gets the uninterpolated variable as-is, and does not know during check, to interpolate it.

Using targ = new String("${TARGET_DATA}") does actively interpolate the string however, as the call to function somehow registers as something active.

However this code does interpolate correctly:

TARGET_DATA= "hello"
targ = "${TARGET_DATA}"

def eq(var1) { return var1 == "hello" }

basic_check = eq(targ)

println "${basic_check}" // resolves as true

which means that at some point, the string is interpolated - possibly the == operation has been reimplemented by Groovy to call String's equality function always:

Such that, Groovy re-implemented the String object - and its equality check - but the <list>.contains() function doesn't use that comparator (or it is not caught during script interpretation, due to being compiled code in the Java standard library) and so fails to trigger the interpolation substitution...

Can someone shed some light here please?

like image 608
tk-noodle Avatar asked Oct 15 '25 20:10

tk-noodle


1 Answers

targ is of type Gstring, rather than a java String. GString retains the information for how to build itself from the interpolated form.

Because targ isn't a String, it will never pass the equality check required by List.contains, where the List contrains a String.

like image 200
Jim Speakman Avatar answered Oct 19 '25 15:10

Jim Speakman



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!