Can a Groovy GString honor an overloaded Map toString implementation?

64 views Asked by At

I maintain a Java library that is used across many different JVM environments, including those that use alternative languages like Groovy.

Within the library, in an upcoming feature branch, there is a class similar to the following:

public class SomeData implements Map<String,Object> {
   // ...
   @Override
   public String toString() {
     // custom implementation here
   }
}

The overridden toString implementation is there specifically to prevent certain security information in the object's values from being exposed in application logs or System.out.println calls accidentally. The data is still necessary however, so it still needs to exist in the object's name/value pairs.

However, if an application developer using the library chooses to write the following in Groovy, the Groovy GString does not honor the overloaded implementation:

def someData = getSomeData()
println "Hi, I have ${someData}"

As discussed in this SO answer, it is because GString bypasses someData#toString() and uses its InvokerHelper instead, presumably iterating over the key value pairs and printing them directly.

This is very undesirable because of the security implications this could have.

There are many reasons why the SomeData implements Map<String,Object> that are not discussed here for brevity, nor is the desire to change the core library API just to appease this behavior in the Groovy programming language.

In short, it's a really poor thing to expect a library implementation to change to make this safer for just Groovy environments, when it's already safe by the existing design.

Is there a way to disable this feature for GString for just instances of the SomeData class?

Is there a reason why GString doesn't check to see if the method is overloaded first before attempting its custom key/value rendering logic?

What workaround, if any, might exist to enable this behavior automatically instead of being forced to tell Groovy users "Sorry, you need to be aware to always call things like this:"

println "Hi, I have ${someData.toString()}"

It's incredibly easy to forget to do this, so any solution should ideally be automatic or enabled via global configuration settings somewhere. Are there any options like this?

0

There are 0 answers