Search code examples
groovytostringgstring

How does Groovy translate from char[] to String within a GString?


I'm trying to figure out how Groovy translates a char[] to a String within a GString.

Example:

char[] pchar = ['p', 'a', 's', 's']
println "$pchar"

Result:

pass

At first I assumed it would use the toString() method on char[] (http://groovy.codehaus.org/groovy-jdk/primitive-types/char[].html#toString()). But the results of running the following code seems to suggest otherwise:

char[] pchar = ['p', 'a', 's', 's']
println "$pchar"

pchar.class.metaClass.toString = {->
    "****"
}

println pchar.toString()
println "$pchar"

Result:

pass

****

pass

I've also tried overriding invokeMethod() to try figuring it out to no avail:

char[] pchar = ['p', 'a', 's', 's']
println "$pchar"

pchar.class.metaClass.toString = {->
    "****"
}
pchar.class.metaClass.invokeMethod = {String methodName, Object arguments ->
    println("Method called on ${delegate.class}: $methodName, $arguments")
    def metaMethod = delegate.metaClass.getMetaMethod(methodName)
    return metaMethod.invoke(delegate, arguments)
}

println pchar.toString()
println "$pchar"

Result:

pass

Method called on class [C: toString, []

****

pass

Does anyone know how Groovy does this transformation?


Solution

  • Browsing through the source, it would appear that the pertinent line is in the source. When instantiating the GString, it creates an Object[] of values that you can see if you get the values property on the GString:

    char[] pchar = ['p', 'a', 's', 's']
    pchar.values // [pass]
    

    In the GString source, it eventually passes the object value (the char[]) to the InvokerHelper write() method, which passes the value to toString(object). In the toString() method you'll find that it doesn't match the criteria and finally passes it to the format() method where on the line in the source it checks if the argument is an array of char and then creates a new String from the char array.

        if (arguments.getClass().isArray()) {
            if (arguments instanceof char[]) {
                return new String((char[]) arguments);
            }
            return format(DefaultTypeTransformation.asCollection(arguments), verbose, maxSize);
        }