Michael J. Lee
Michael J. Lee

Reputation: 12406

Evaluate GString at runtime with domain class binding

I'd like to store a user configurable GString that would be bound to a domain class but I'm having a problem finding a nice solution to this.

Example (concept/pseudo/non-working)

class Person{
    ...

    String displayFooAs;  //<-- contains a java.lang.String like '${name} - ${address}'
}


class Foo{

    String name;
    String address;
    String city;

    public String getDisplayAs(def person){

        return doStuff(this, person.displayFooAs); //<-- Looking for something simple.

    }



}

UPDATE:

After review I've decided that this kind of flexibility would pose a security risk. It would allow users to essentially script out sql injection into 'dispalyFooAs'. Back to the drawing board.

Upvotes: 1

Views: 1113

Answers (3)

Aly Martin
Aly Martin

Reputation: 113

I needed something similar where I would evaluate the GString inside a closure loop so the template references it property values. I took the example above and formalized it into a standardized class for late GString evaluations.

import groovy.text.SimpleTemplateEngine

class EvalGString {
    def it
    def engine

    public EvalGString() {
        engine = new SimpleTemplateEngine()
    }

    String toString(template, props) {
        this.it = props
        engine.createTemplate(template).make(this.properties).toString()        
    }
}    

def template = 'Name: ${it.name} Id: ${it.id}'
def eval = new EvalGString()

println eval.toString(template, [id:100, name:'John')
println eval.toString(template, [id:200, name:'Nate')

Output:

Name: John Id: 100

Name: Nate Id: 200

Upvotes: 0

tim_yates
tim_yates

Reputation: 171084

Do you mean like:

public String getDisplayAs(def person){
  doStuff( this, person?.displayFooAs ?: "$name - $address" )
}

This works in Groovy, but I've never embedded SimpleTemplateEngine into something like this in Grails, so would require extensive testing to make sure it works as expected and doesn't gobble memory.

import groovy.text.SimpleTemplateEngine

class Person {
  String displayAs = 'Person $name'
}

class Foo {
  String name = 'tim'
  String address = 'yates'

  String getDisplayAs( Person person ) {
    new SimpleTemplateEngine()
          .createTemplate( person?.displayAs ?: '$name - $address' )
          .make( this.properties )
          .toString()
  }
}

def foo = new Foo()

assert foo.getDisplayAs( null )         == 'tim - yates'
assert foo.getDisplayAs( new Person() ) == 'Person tim'

Upvotes: 1

Mr. Cat
Mr. Cat

Reputation: 3552

You've defined

private static final String DEFAULT_DISPLAY_AS = '${name} - ${address}'

static and final - of course it doesn't work?

Define it's as closure

private def DEFAULT_DISPLAY_AS = {->'${name} - ${address}'}

and call in code

DEFAULT_DISPLAY_AS()

Upvotes: 0

Related Questions