将对象属性复制到Groovy

时间:2017-10-26 10:53:35

标签: java groovy

我正在使用一种时髦的方式来建议: https://stackoverflow.com/a/9072974/4470135 所以我的代码是:

def copyProperties(source, target) {
    def (sProps, tProps) = [source, target]*.properties*.keySet()
    def commonProps = sProps.intersect(tProps) - ['class', 'metaClass']
    commonProps.each { target[it] = source[it] }
}

当我尝试调用应该将实体转换为Dto的方法时,我得到的是:

  

没有方法签名:java.util.ArrayList.keySet()适用   对于参数类型:()值:[] \ n可能的解决方案:toSet(),   toSet(),set(int,java.lang.Object),set(int,java.lang.Object),   get(int),get(int)

更新

我的源代码是一个Serializable bean,其字段为:

private String passengerName;
@NotNull
@Size(min = 5, max = 40)
private String destination;
@NotNull
private String departureDate;

我的目标是具有相同字段的JPA实体,但有一个额外的@Id字段和稍有不同的日期表示:

@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
ZonedDateTime departureDate  

2 个答案:

答案 0 :(得分:0)

代码正在运行,但是,有可能会破坏的极端情况。

要解决此问题,请使用方法调用properties替换属性访问getProperties(),这可能足以满足您的需求。为了涵盖所有情况,您需要编写特殊情况的代码(见底部)

原始版本的工作示例

def copyProperties(source, target) {
    def (sProps, tProps) = [source, target]*.properties*.keySet()
    def commonProps = sProps.intersect(tProps) - ['class', 'metaClass']
    commonProps.each { target[it] = source[it] }
}

def a = new Expando()
a.foo = "foo"
a.bar = "bar"

def b = new Expando()
b.baz = "baz"
b.bar = "old"

copyProperties(a, b)

println b

导致问题的示例

如果参数有一个名为properties的属性,我会得到相同的异常(如果值为List):

def c = new Expando()
c.properties = []
c.bar = "bar"

def d = new Expando()
d.baz = "baz"
d.bar = "old"

copyProperties(c, d)

println d

两种情况都有效:

def copyProperties(source, target) {
    def (sProps, tProps) = [source, target]*.getProperties()*.keySet()
    def commonProps = sProps.intersect(tProps) - ['class', 'metaClass']
    commonProps.each { target[it] = source[it] }
}

不是在这里,我使用了对getProperties的显式调用,而不仅仅是访问properties属性。

我们仍然可以打破此

def e = new Object() {
    // causes same Exception again
    def getProperties() {
        return []
    }

    def bar = "bar"
}

def f = new Expando()
f.baz = "baz"
f.bar = "old"

copyProperties(e, f)

您可以通过显式使用metaClass来修复e的最后一个示例

def copyProperties(source, target) {
    def (sProps, tProps) = [source, target]*.getMetaClass()*.properties*.name
    def commonProps = sProps.intersect(tProps) - ['class', 'metaClass']
    commonProps.each { target[it] = source[it] }
}

但是,由于f会失败。

处理特殊情况

def getProperties(Expando obj) {
    return obj.getProperties().keySet()
}

def getProperties(Object obj) {
    return obj.getMetaClass()*.properties*.name
}

def copyProperties(source, target) {
    def (sProps, tProps) = [source, target].collect {getProperties(it)}
    def commonProps = sProps.intersect(tProps) - ['class', 'metaClass']
    commonProps.each { target[it] = source[it] }
}

在这里,我们提供需要特殊处理的物品;) 请注意,这仅适用于具有@CompileDynamic的groovy,因为将在运行时调用getProperties实现。替代方案是对所有案例进行instanceof检查。

答案 1 :(得分:0)

User user = User.findById('1')
User copyUser = new User()
InvokerHelper.setProperties(copyUser, user.properties)