Today I learned how Groovy treats strings
when comparing it to an integer. I was new to the language and just
occasionally use it for some Jenkins Pipeline-related tasks.
The Bug
Note this is an oversimplification of what our pipeline code does
def numOfHours = "3"
if (numOfHours > 0) {
def numOfHoursParsed = numOfHours as Integer
// Some integer operations
println "Greater than 0"
}
This specific code works, but can you find the bug?
Yes, in the if statement we do a check if numOfHours
is greater than 0 even though it is a string. This surprisingly worked in the specific example where we have “3” as the numOfHours
. You can see that only after the check do we do the casting or conversion.
We were wondering and debugging for hours but were blindsided by this check. In our code numOfHours
was not an obvious string.
Upon trying different parameters we concluded that this check only returns true if the number is a single-digit number. We found out that numbers ‘1’, ‘3’ and other single-digit numbers worked as expected, but when trying out two-digit numbers we would always get a java.lang.ClassCastException
.
What?
I guess this is how Groovy does a comparison of string to an integer?
See the following code snippet:
if ("9" > 0) {
print "9 is greater than 0"
} else {
print "9 is not greater than 0"
}
// -> 9 is greater than 0
if ("11" > 0) {
print "11 is greater than 0"
} else {
print "11 is not greater than 0"
}
// -> java.lang.ClassCastException
...
The Fix
Well, the obvious fix is to convert the string to an integer before we do the comparison and other operations.
def numOfHoursParsed = numOfHours as Integer
if (numOfHoursParsed > 0) {
// Use numOfHoursParsed here
// Some integer operations
println "Greater than 0"
}
Lessons learned!
Make sure types are converted before doing an integer comparison!