Java 将对象属性复制到Groovy中的另一个对象

Java 将对象属性复制到Groovy中的另一个对象,java,groovy,Java,Groovy,我是用一种时髦的方式来做这件事的: 所以我的代码是: 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 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), 获取(int),获取(int)

更新:

我的源代码是一个具有以下字段的可序列化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  

代码正在运行,但是,在某些情况下,它可能会中断

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

原始版本的工作示例

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
导致问题的示例

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)
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] }
}
如果参数有一个名为
properties
的属性,我会得到与您相同的异常(如果该值是
列表
):

在这两种情况下都有效的方法:

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)
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] }
}
通过显式使用元类,可以修复
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 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)
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
进行检查。

能否将实体和数据粘贴到类中?另外,显示一个复制到另一个的示例也会有所帮助。这可能与您调用
copyProperties
的方式有关。我把你的版本和原来的线程混合在一起,效果很好。不管怎样,我还是会选择那篇文章的第一个版本<代码>属性还返回值(例如昂贵的getter)。顺便说一句,第一个版本可以工作。多么详细的答案啊!谢谢,@Mene!很有趣,希望有帮助;)
User user = User.findById('1')
User copyUser = new User()
InvokerHelper.setProperties(copyUser, user.properties)