从地图更新groovy对象字段

Clé*_*des 9 groovy

在groovy中,我们可以轻松地从地图创建对象并自动填充相应的字段:

def myAddress = new Address([street:"King's street", number:"1200"])
Run Code Online (Sandbox Code Playgroud)

是否也可以从地图更新现有对象而无需重新创建它?就像是...

myAddress.update([zip: "30555050", city: "London"])
Run Code Online (Sandbox Code Playgroud)

Ran*_*niz 10

您可以使用object."${variable}"访问器执行此操作:

map.each { key, value ->
    object."${key}" = value
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以创建一个方法来执行此操作并将其安装在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
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 作为一个受到启发的工作.在boostrap.groovy(对于Grails应用程序)上实现它似乎可以完成这项工作.谢谢. (2认同)

Bil*_*l K 6

在查找/学习 Szymon 的优秀答案并找到调用帮助器的不同方法之后,答案似乎可以简化为:

InvokerHelper.setProperties(myAddress, [zip: "30555050", city: "London"])"

这与您的要求非常接近

myAddress.update([zip: "30555050", city: "London"])

我将此作为对他的问题的评论添加,但它太简单了,我认为它值得一个简洁的顶级答案。


Szy*_*iak 5

您可以使用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'
Run Code Online (Sandbox Code Playgroud)

尽管如果您可以避免使用可变对象,那对您来说更好。否则,您必须考虑线程安全,以免遇到并发问题。您可以使用前面的示例创建一个需要 2 个参数的静态方法:现有对象和要更新的属性映射。结果,您将获得一个包含更新字段的新实例。你也可以让你的班级成为一个不可变的班级。