更新地图中的 groovy 个对象字段
Updating groovy object fields from a map
在groovy中,我们可以轻松地从地图创建对象并自动填充相应的字段:
def myAddress = new Address([street:"King's street", number:"1200"])
是否可以在不重新创建地图的情况下更新地图中的现有对象?像...
myAddress.update([zip: "30555050", city: "London"])
您可以使用 InvokeHelper 类别和 setProperties 方法,这里是一个简短的例子:
import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString
import org.codehaus.groovy.runtime.InvokerHelper
@EqualsAndHashCode
@ToString
class Address {
String street
String number
String city
}
Address mainAddress = new Address(street: 'Test', number: '2B', city: 'London')
use InvokerHelper, {
mainAddress.setProperties([street: 'Lorem', number: 'Ipsum'])
}
assert mainAddress.street == 'Lorem'
assert mainAddress.number == 'Ipsum'
assert mainAddress.city == 'London'
虽然如果你能避免可变对象,那对你来说更好。否则你要考虑线程安全不要运行陷入并发问题。您可以使用前面的示例创建一个需要 2 个参数的静态方法:现有对象和要更新的属性映射。结果您得到一个包含更新字段的新实例。你也可以让你的 class 成为不可变的。
您可以使用 object."${variable}"
访问器来执行此操作:
map.each { key, value ->
object."${key}" = value
}
然后您可以创建一个执行此操作的方法并将其安装在 Object.metaClass 上,它将随处可用:
@Canonical
class MapSet {
String name
int count
static def setAttributesFromMap(Object o, Map<String, Object> map) {
map.each { key, value ->
o."${key}" = value
}
}
static void main(String[] args) {
Object.metaClass.update = {
setAttributesFromMap delegate, it
}
def o = new MapSet([
name: "foo",
count: 5
])
assert o.name == "foo"
assert o.count == 5
o.update([
name: "bar",
count: 6
])
assert o.name == "bar"
assert o.count == 6
}
}
从 Szymon 的优秀答案中查看 up/learning 并找到调用助手的不同方法后,答案似乎可以简化为:
InvokerHelper.setProperties(myAddress, [zip: "30555050", city: "London"])"
这与您的要求非常接近
myAddress.update([zip: "30555050", city: "London"])
我将此添加为对他的问题的评论,但它非常简单,我认为它应该得到一个简洁的顶级答案。
在groovy中,我们可以轻松地从地图创建对象并自动填充相应的字段:
def myAddress = new Address([street:"King's street", number:"1200"])
是否可以在不重新创建地图的情况下更新地图中的现有对象?像...
myAddress.update([zip: "30555050", city: "London"])
您可以使用 InvokeHelper 类别和 setProperties 方法,这里是一个简短的例子:
import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString
import org.codehaus.groovy.runtime.InvokerHelper
@EqualsAndHashCode
@ToString
class Address {
String street
String number
String city
}
Address mainAddress = new Address(street: 'Test', number: '2B', city: 'London')
use InvokerHelper, {
mainAddress.setProperties([street: 'Lorem', number: 'Ipsum'])
}
assert mainAddress.street == 'Lorem'
assert mainAddress.number == 'Ipsum'
assert mainAddress.city == 'London'
虽然如果你能避免可变对象,那对你来说更好。否则你要考虑线程安全不要运行陷入并发问题。您可以使用前面的示例创建一个需要 2 个参数的静态方法:现有对象和要更新的属性映射。结果您得到一个包含更新字段的新实例。你也可以让你的 class 成为不可变的。
您可以使用 object."${variable}"
访问器来执行此操作:
map.each { key, value ->
object."${key}" = value
}
然后您可以创建一个执行此操作的方法并将其安装在 Object.metaClass 上,它将随处可用:
@Canonical
class MapSet {
String name
int count
static def setAttributesFromMap(Object o, Map<String, Object> map) {
map.each { key, value ->
o."${key}" = value
}
}
static void main(String[] args) {
Object.metaClass.update = {
setAttributesFromMap delegate, it
}
def o = new MapSet([
name: "foo",
count: 5
])
assert o.name == "foo"
assert o.count == 5
o.update([
name: "bar",
count: 6
])
assert o.name == "bar"
assert o.count == 6
}
}
从 Szymon 的优秀答案中查看 up/learning 并找到调用助手的不同方法后,答案似乎可以简化为:
InvokerHelper.setProperties(myAddress, [zip: "30555050", city: "London"])"
这与您的要求非常接近
myAddress.update([zip: "30555050", city: "London"])
我将此添加为对他的问题的评论,但它非常简单,我认为它应该得到一个简洁的顶级答案。