0

I have this stub of code to add dynamic attributes. I work with mongodb and i want to add the properties dynamically. This is what i tried to do when unit testing.

User.metaClass.dynamicAttributes = [:]

User.metaClass.propertyMissing = { String name ->
    delegate.dynamicAttributes[name]
}

User.metaClass.propertyMissing = { String name, value ->
    delegate.dynamicAttributes[name] = value
}

But this fails and i am stepping over my patience limit!

User u = new User()
u.ppt = 0

User u2 = new User()
u2.ppt = 1

assert u2.ppt == 1
assert u.ppt == 0 // fails here, println shows that u.ppt is also 1! 
Amanuel Nega
  • 1,899
  • 1
  • 24
  • 42

2 Answers2

1

The issue here is that your concept is completely flawed. You are assigning a map to the Class and not the instance with this line:

User.metaClass.dynamicAttributes = [:]

In order to accomplish what you are looking to do you need to do the following:

User.metaClass.propertyMissing = { String name ->
  if (!delegate.dynamicAttributes) delegate.dynamicAttributes = [:]
  delegate.dynamicAttributes[name] 
}  
User.metaClass.propertyMissing = { String name, value ->     
  if (!delegate.dynamicAttributes) delegate.dynamicAttributes = [:]
  delegate.dynamicAttributes[name] = value 
}

I'm sure there is a cleaner way to do this but the above demonstrates a solution where the map is instanced per instance and not across all instances.

Joshua Moore
  • 24,706
  • 6
  • 50
  • 73
0

changing this

User.metaClass.dynamicAttributes = [:]

User.metaClass.propertyMissing = { String name ->
    delegate.dynamicAttributes[name]
}

User.metaClass.propertyMissing = { String name, value ->
    delegate.dynamicAttributes[name] = value
}

to this

User.metaClass.propertyMissing = { String name ->
    if (!delegate.metaClass.hasProperty('dynamicAttributes') delegate.metaClass.dynamicAttributes = [:]
    delegate.dynamicAttributes[name]
}

User.metaClass.propertyMissing = { String name, value ->
    if (!delegate.metaClass.hasProperty('dynamicAttributes') delegate.metaClass.dynamicAttributes = [:]
    delegate.dynamicAttributes[name] = value
}

Solved it! I am not sure, but it seems like groovy shares the attribute put through metaClass!

Amanuel Nega
  • 1,899
  • 1
  • 24
  • 42