Christian Bongiorno
Christian Bongiorno

Reputation: 5648

Groovy: Proper way to create/use this class

I am loading a groovy script and I need the following class:

import java.util.function.Function
import java.util.function.Supplier

class MaskingPrintStream extends PrintStream {


    private final Function<String,String> subFunction
    private final Supplier<String> secretText

    public MaskingPrintStream(PrintStream out, Supplier<String> secretText, Function<String,String> subFunction) {
        super(out);
        this.subFunction = subFunction;
        this.secretText = secretText;
    }

    @Override
    public void write(byte b[], int off, int len)  {
        String out = new String(b,off,len);
        String secret = secretText.get();
        byte[] dump = out.replace(secret, subFunction.apply(secret)).getBytes();
        super.write(dump,0,dump.length);
    }
}

right now I have it in a file called MaskingPrintStream.groovy. But, by doing this I effectively can only access this class as an inner class of the class that gets created by default that corresponds to the file name.

What I want to work is code more like this:

def stream = evaluate(new File(ClassLoader.getSystemResource('MaskingPrintStream.groovy').file))

But as you can see, I need to give it some values before it's ready. Perhaps I could load the class into the JVM (not sure how from another groovy script) and then instantiate it the old-fashioned way?

The other problem is: How do I set it up so I don't have this nested class arrangement?

Upvotes: 0

Views: 195

Answers (1)

Dmytro Buryak
Dmytro Buryak

Reputation: 368

groovy.lang.Script#evaluate(java.lang.String) has a bit different purpose.

For your case you need to use groovy.lang.GroovyClassLoader that is able to parse groovy classes from source, compile and load them. Here's example for your code:

def groovyClassLoader = new GroovyClassLoader(this.class.classLoader) // keep for loading other classes as well
groovyClassLoader.parseClass('MaskingPrintStream.groovy')

def buf = new ByteArrayOutputStream()
def maskingStream = new MaskingPrintStream(new PrintStream(buf), { 'secret' }, { 'XXXXX' })
maskingStream.with {
    append 'some text '
    append 'secret '
    append 'super-duper secret '
    append 'other text'
}
maskingStream.close()

println "buf = ${buf}"

And the output it produces in bash shell:

> ./my-script.groovy
buf = some text XXXXX super-duper XXXXX other text

Upvotes: 1

Related Questions