4

Is there a way to bind properties from one instance of a class to the properties of an instance of another class (the common fields between the two). See the example below:

class One {
  String foo
  String bar
}

class Two {
  String foo
  String bar
  String baz
}

def one = new One(foo:'one-foo', bar:'one-bar')
def two = new Two()

two.properties = one.properties

assert "one-foo" == two.foo
assert "one-bar" == two.bar
assert !two.baz

The result is an error: Cannot set readonly property: properties for class: Two

vv.
  • 65
  • 1
  • 5

2 Answers2

9

I would choose InvokerHelper.setProperties as I suggesed here.

use(InvokerHelper) {
    two.setProperties(one.properties)
}
Community
  • 1
  • 1
Michal Zmuda
  • 5,381
  • 3
  • 43
  • 39
  • Does this handles `metaClass` and `class` properties safely? I mean, NOT overwriting them? – Nikem Jan 07 '16 at 14:58
  • @Nikem This approach will not override metaClass or class. `import org.codehaus.groovy.runtime.InvokerHelper class A { String foo String bar } class B { String foo } A a = new A(foo: 'foo', bar: 'bar')​​​​​​ ​B b = new B() use(InvokerHelper) { b.setProperties(a.properties) } println b.properties​ // [foo:foo, class:class B] ` – Igor Aug 01 '18 at 15:14
6

The problem is that for every object, .properties includes two built-in Groovy-defined properties, these are the metaClass and class. What you want to do is only set the user-defined properties. You can easily do this using code such as that shown below:

class One {
  String foo
  String bar
}

class Two {
  String foo
  String bar
  String baz
}

def one = new One(foo:'one-foo', bar:'one-bar')

// You'll probably want to define a helper method that does the following 3 lines for any Groovy object
def propsMap = one.properties
propsMap.remove('metaClass')
propsMap.remove('class')

def two = new Two(propsMap)

assert "one-foo" == two.foo
assert "one-bar" == two.bar
assert !two.baz
Dónal
  • 185,044
  • 174
  • 569
  • 824
  • I am curious about the general approach. I have a web app connecting to a datawarehouse. The domain of the web app is quite different from the tables and data coming from the warehouse. I intend to use the above technic probably in the service layer but would you recommend to have an additional layer responsible to transform legacy objects to your domain objects? – ontk Jun 07 '12 at 17:45
  • This doesnt work the other way around since baz property is not defined on One – dbrin Mar 12 '15 at 00:30