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:
targ
, the content of that variable isn't updated. At this stage, targ still contains a literal placeholder stringMy 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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With