Reputation: 1482
So in groovy you can define a string whos value is retrieved lazily each time its value is read.
System.setProperty('foo', 'bar')
def getMyValue = {
return System.getProperty('foo')
}
def myData = [
value1: "${ getMyValue() }",
vaule2: "${ -> getMyValue() }",
]
System.setProperty('foo', 'bam')
println "${myData}"
System.setProperty('foo', 'baz')
println "${myData}"
When ran this yields
[value1:bar, vaule2:bam]
[value1:bar, vaule2:baz]
This is really nice for values that are Strings
What I would like to know if it is possible to do something similar for number types
def myData = [
myInt: { -> Integer.valueOf(System.getProperty('somePropThatIsSetDownStream')) },
]
Or if there is way to override the get method on the map so that when get is performed I could execute a closure that transforms the value of myData.myInt
def valueTransformer = { key, map ->
if(map[key] instanceOf Closure) {
return map[key].call()
}
return map[key]
}
Is there away to maybe have a closure that overrides the logic that happens when myData.myInt is called?
Upvotes: 2
Views: 2233
Reputation: 28564
it depends on syntax you want to achieve but there are could be a lot of solutions.
I suggest to implement Lazy closure class where toString will call the closure
@groovy.transform.CompileStatic
class Lazy extends Closure{
@Delegate private Closure closure
Lazy(Closure c){
super(c.getOwner(), c.getThisObject())
this.closure=c
}
static Lazy of(Closure c){ new Lazy(c) }
Object doCall(){ closure.call() }
String toString(){ closure.call() as String }
}
def myData = [
myInt: Lazy.of{ System.currentTimeMillis() },
]
//different printouts
println myData.myInt //toString called
Thread.sleep(100)
println myData.myInt() //returns the value (not string)
Thread.sleep(100)
println myData
result:
1576168290790
1576168290901
[myInt:1576168291003]
Upvotes: 2