techHenson
techHenson

Reputation: 93

How can I pass a class to Groovy's Eval binding?

I'm doing some gross stuff, like using Groovy's metaClass and Eval to dynamically assign properties to an object from an XML import:

class ObjectBuilder {
  def assignProp(String propName, String propValue) {
    Eval.x(this, "x.metaClass.${propName} = '${propValue}'")     
  }
}

def h = new ObjectBuilder()
h.assignProp('name', 'Henson')
println(h.name)

What I'd like to do though, is be able instantiate another copy of the class inside itself:

Eval.x(this, "x.metaClass.${ObjName} = new ObjectBuilder()")

But I can't, because I think the class isn't passed to the binding. Is there another solution?

Upvotes: 0

Views: 481

Answers (2)

Will
Will

Reputation: 14549

A couple of solutions:

Expando

You may try working with a bunch of Expandos:

h = new Expando()
h.last = new Expando()
h.last.name = 'tech'

assert h.last.name == 'tech'

Metaclass the object directly

xml = '''
<person>
  <name>john</name>
  <surname>doe</surname>
  <age>41</age>
  <location>St Louis, MO</location>
</person>
'''

class Person {
  def name, surname, location, age
}

root = new XmlParser().parseText xml

person = new Person(root.children().collectEntries { [it.name(), it.text()] })

person.metaClass.getFullname = { "$delegate.name $delegate.surname" }

assert person.fullname == "john doe"

person.metaClass.likes = "chicken with lemon"

assert person.likes == "chicken with lemon" 

Maps

map = [:]
map.last = [:]
map.last.name = 'Tech'
assert map.last.name == 'Tech'

Upvotes: 2

techHenson
techHenson

Reputation: 93

Passing a newly instantiated object then assigning it with Eval seems to work:

class ObjectBuilder {
  def assignProp(String propName, String propValue) {
    Eval.x(this, "x.metaClass.${propName} = '${propValue}'")     
  }
  def nestObj(String objName) {
    Eval.xy(this, new ObjectBuilder(), "x.metaClass.${objName} = y")
  }
}

ObjectBuilder h = new ObjectBuilder()
h.assignProp('name', 'Henson')
h.nestObj('last')
h.last.assignProp('name', 'Tech')

println h.name + ' ' + h.last.name

Upvotes: 1

Related Questions