Lets assume I have a domain class called Template that looks somewhat like this:
class Template{
String subject
...
}
I save an instance of this class:
Template t=new Template(subject:'Hello ${name}').save()
Now, I fetch this instance inside a method as follows:
def render(Long id){
String name='foo'
Template t= Template.get(id)
println t.subject
}
I want the "println t.subject" to be printed as "Hello foo". What I get is "Hello ${name}".
I want t.subject to dynamically replace the value of variable name - "foo" in place of ${name}.
Can this be achieved in groovy?
I cannot find any documentation of how to do this, or why this cannot be done.
Update:
I tried this on my GroovyConsole.
class Entity{
String name
}
class Template{
String name
String subject
}
String renderTemplate(Template template, Entity entity){
return template.subject
}
Entity e = new Entity(name:'product')
Template template=new Template(name:'emailTemplate',subject:'Product ${e.name}')
renderTemplate(template,e)
The Output I got was:
Result: Product product
class Template {
String subject
// ...
}
Template t = new Template(subject: 'Hello, ${name}').save()
Important: Use single quotes in 'Hello, ${name}' or you will get an error.
def render(Long id) {
String name = "world"
Template t = Template.get(id)
def engine = new groovy.text.GStringTemplateEngine()
def subject = engine
.createTemplate(t.subject)
.make(name: name)
println subject
}
There are a couple of things wrong with the code shown. You have this:
class Template{
String subject
...
}
Then you have this:
Template t=new Template(subject:"Hello ${name}").save()
The Groovy String assigned to the subject property will be evaluated as soon as you assign it to subject because subject is a String. The actual value will depend on the value of the name property that is in scope when that code executes.
Later you have this:
def render(Long id){
String name="foo"
Template t= Template.get(id)
println t.subject
}
It looks like you are wanting that local name property to be substituted into a Groovy String that has been assigned to t.subject, but that isn't how Groovy works. t.subject is not a Groovy String. It is a String.
Separate from that you comment that when you println t.subject that the output is "Hello ${name}". I don't think that is possible, but if that is what you are seeing, then I guess it is.
You can use a transient property to emulate the required behavior:
class Template{
String subject
String getSubjectPretty(){ "Hello $subject" }
static transients = ['subjectPretty']
}
Then you can use:
println Template.get(1).subjectPretty
Related
I am wondering if I can pass variable to be evaluated as String inside gstring evaluation.
simplest example will be some thing like
def var ='person.lName'
def value = "${var}"
println(value)
I am looking to get output the value of lastName in the person instance. As a last resort I can use reflection, but wondering there should be some thing simpler in groovy, that I am not aware of.
Can you try:
def var = Eval.me( 'new Date()' )
In place of the first line in your example.
The Eval class is documented here
edit
I am guessing (from your updated question) that you have a person variable, and then people are passing in a String like person.lName , and you want to return the lName property of that class?
Can you try something like this using GroovyShell?
// Assuming we have a Person class
class Person {
String fName
String lName
}
// And a variable 'person' stored in the binding of the script
person = new Person( fName:'tim', lName:'yates' )
// And given a command string to execute
def commandString = 'person.lName'
GroovyShell shell = new GroovyShell( binding )
def result = shell.evaluate( commandString )
Or this, using direct string parsing and property access
// Assuming we have a Person class
class Person {
String fName
String lName
}
// And a variable 'person' stored in the binding of the script
person = new Person( fName:'tim', lName:'yates' )
// And given a command string to execute
def commandString = 'person.lName'
// Split the command string into a list based on '.', and inject starting with null
def result = commandString.split( /\./ ).inject( null ) { curr, prop ->
// if curr is null, then return the property from the binding
// Otherwise try to get the given property from the curr object
curr?."$prop" ?: binding[ prop ]
}
I know that to access a variable from within the Config.groovy file,
grailsApplication.config.someValue.anotherValue
I want to use a variable within this path because I want to get a URL from the config file. The value foo is passed in as a parameter to the method which will be called a number of times using different variables based on other factors.
def foo = "anothervalue"
grailsApplication.config.someValue.${ foo }.
The actual path to the value I want in the config stays the same as in the first instance.
I have tried:
grailsApplication.config.someValue.${ foo }
grailsApplication.config.someValue${ foo }
grailsApplication.config.someValue + "${ foo }"
grailsApplication.config.someValue + ".${ foo }"
grailsApplication.config.someValue + ${ foo }
grailsApplication.config.someValue."${ foo }" must works.
grailsApplication.config returns a groovy.util.ConfigObject like groovy.util.ConfigSlurper.parse() so you can see how it works in the follow example:
import groovy.util.ConfigSlurper
def configTxt = '''
prop1 {
prop2 {
person.name = 'paco'
}
}
'''
def config = new ConfigSlurper().parse(configTxt)
def foo = "prop2"
println config.prop1."${foo}" // prints [person:[name:paco]]
Hope this helps,
more natural would be grailsApplication.config.someValue[ foo ]
I wanted to set a value to a field in domain class.
For example,
class Example {
String name
String lastName
}
Now, from response I'm getting domain name, object instance id, field name and value. I have to set the value to the field in domain class.
Here I got the values as
domainName = 'Example'
instanceId = 1
fieldName = 'name'
valueToSet = 'XYZ'
So how should I set value to the field name? May be this is simple but I'm a new with grails and groovy.
Based on the domain name, a new domain instance has to be created at runtime. For this to happen, grailsApplication has to be injected. Here is a sample which can be modeled after in Controller or a Service class:
class SomeService {
def grailsApplication
def someMethod(String domainName, long instanceId,
String fieldName, def valueToSet) {
Class domainClazz = grailsApplication.domainClasses.find {
it.clazz.simpleName == domainName
}.clazz
def domainInstance = domainClazz.get( instanceId )
domainInstance."$fieldName" = valueToSet
domainInstance.save()
}
}
You can populate a Grails domain class by assigning a map to its properties, for example from the params in the controller (using that handy automatic binding). E.g.:
ded example=new Example()
example.properties=params
So you can see from this that the domain object can be treated as a set of properties. Which means you can use strings for keys, so you might have something like:
example['name']='XYZ'
I don't know whether that's what you're asking but I hope it helps.
How to add a String type field to class (i.e to all instances of that class), like grails add an id and version fields to all domain classes? If it is possible, how to specify the type of field as String / Long etc
EDIT:
The added fields are not updated in DB. how to make them persistent?
With respect to POGO, you can use ExpandoMetaClass to add/override a property/field/constructor.
class Foo{
String bar
}
//Add a field to Foo at runtime
//Type is set to String in this case
Foo.metaClass.baz = "Hello World"
//Add a method to Foo at runtime
Foo.metaClass.doSomething = {String str -> str.reverse()}
assert new Foo().baz == "Hello World"
assert new Foo().doSomething("Hello") == "olleH"
For your use case, you may be able to use normal inheritance:
abstract class Base {
// common fields
// constraints for those fields
// etc.
}
class MyDomain extends Base {
}
i am trying to call a closure over each object of a class, and then displaying the objects which returned by the closure.
the closure is:
def activitiesPlanned={
cal.set(this.plannedStartDate)
def planDateMonth=cal.get(Calendar.MONTH)
def planDateYear=cal.get(Calendar.YEAR)
}
the call i made is:
def getActivitiesPlanned(int month,int year){
countActivitiesPlanned=ProgressData.each{it.activitiesPlanned.findAllWhere(planDateMonth:month,planDateYear:year).count()}
println countActivitiesPlanned
}
Domain Class //EDIT
package main
class ProgressData {
//String milestoneName
String taskId //Added later
String taskDescription
String taskCategory
Integer plannedHours
Integer actualHours
Date plannedStartDate
Date actualStartDate
Date plannedEndDate
Date actualEndDate
Integer stepsCreated=0
Integer stepsExecuted=0
String status //Originally Completed
String assignedTo
//String unplanned
String accepted //Added later
def ProgressData(){}
static constraints = {
//milestoneName(blank:false)
taskDescription(blank:false)
taskCategory(blank:false)
plannedHours(blank:false)
actualHours(blank:false)
id generator:"assigned",name:"taskId"
}
Calendar cal=Calendar.getInstance()
def activitiesPlanned={
cal.set(this.plannedStartDate)
def planDateMonth=cal.get(Calendar.MONTH)
def planDateYear=cal.get(Calendar.YEAR)
}
static hasMany=[defects:DefectData]
}
I am getting: "No such property: activitiesPlanned for class: main.ProgressData Possible solutions: activitiesPlanned". what issue may be there?
I think you don't want .each{} rather .sum{}
Example:
def listThing = [1,2,3]
def sumOfList = listThing.sum{it}
assert sumOfList == 6
Also ProgressData is a Domain Class so you can't use .each{} on it. You have to do ProgressData.list().each{ and by that I really mean ProgressData.list().sum{ for what I think you're trying to do.
Also, that activitiesPlanned closure doesn't return any activities...