Search code examples
jenkinsgroovyjenkins-groovy

Why does this `join` method call with no arguments succeed?


This Groovy script looks simple enough:

def a = [].join()
println a

I would expect it to throw MissingMethodException because join method requires a parameter, if I'm looking at the right one, but it works just fine. And here is the source code for that method, so the parameter is definitely not optional. You know where it fails the way I expect it to? In Jenkins, of course.

So, why does it work? Is there some Groovy convention I don't know about? Or does it actually call a different method?


Solution

  • I think you are providing the parameter, but it is null. You are in the end calling this method in DefaultGroovyMethods class:

    public static String join(Iterator<?> self, String separator) {
            if (separator == null) {
                separator = "";
            }
    ...
    

    While default groovy methods are injected into all Groovy objects (you can find this information here among comments) I assume first parameter is always populated by the fact of injecting it to iterable while the second as you can see is set to be empty string when it is null. Thus [].join() in my opinion passes empty list and null to the join method and it effectively means setting empty string as separator.

    EDIT: Yes, you are right we could do more digging on the subject. For sure Groovy assumes null was passed when function requiring 1 parameter (but not primitive type) is called without parameters:

    def f1(String a){
        println a
    }
    
    f1() // prints word "null"
    

    Here is some info from somebody who spotted it 8 years ago as well. I am sure this is your missing puzzle - giving no parameters causes Groovy to pass null when parameter is not of primitive type. I do not know how mechanism of injecting default groovy methods makes possible for join method to accept Iterable but String parameter behaviour should be clear now. Isn't it?