"仅复制如果存在模式"在Groovy?

时间:2015-08-08 00:26:22

标签: java groovy copy mapping dozer

我有一种情况需要将一个POJO实例的内容(属性)复制到同一类型的另一个实例,但仅适用于非null属性/成员和非空集合。例如:

// Groovy pseudo-code
class Widget {
    Fizz fizz
    List<Buzz> buzzes
    List<Foo> foos

    Widget(Fizz fizz, List<Buzz> buzzes, List<Foo> foos) {
        super()

        this.fizz = fizz
        this.buzz = buzz
        this.foos = foos
    }
}

class ExistentialCopier<T> {
    T copyExistentialContents(T toCopy) {
        // ???
    }
}

class Driver {
    static void main(String[] args) {
        ExistentialCopier<Widget> widgetCopier = new ExistentialCopier<Widget>()

        Fizz fizz = new Fizz()

        Buzz b1, b2, b3
        b1 = new Buzz()
        b2 = null            // <— note the NULL
        b3 = new Buzz()
        List<Buzz> buzzes = []
        buzzes << b1
        buzzes << b2
        buzzes << b3

        Widget w1 = new Widget(fizz, buzzes, null)
        Widget w2 = widgetCopier.copyExistentialContents(w1)

        // All of these return true.
        assert w2.fizz == w1.fizz
        assert w2.buzzes.get(0) == w1.buzzes.get(0)
        assert w2.buzzes.get(1) == w1.buzzes.get(2) // because b2 was null, it didn’t copy over
        assert w2.size() == 2 // again, b2 didn’t copy (it was null/nonexistent)
        assert w2.fizzes == null
    }
}

所以我在ExistentialCopier寻找的是:

  • 一种通用的方法并处理任何类型,Widgets或其他类型(也许是T泛型将需要实现一些接口(?)
  • 对于非集合,请复制toCopy的非空属性
  • 对于集合,如果toCopy的集合为空,请不要复制它(将副本的相应集合也调为null)
  • 对于集合,如果特定元素/成员为null,请不要复制它,否则复制它

我觉得有一种 Groovy 方法可以实现这一点,但也许这种类型的“仅存在复制”模式是众所周知的,并且已经被一些开源库解决了。也许最适合像Dozer null exclusions这样的bean-to-bean映射实用程序的解决方案(我没有经验)?

1 个答案:

答案 0 :(得分:2)

我不知道预先存在的功能或库,但您可以使用metaprogramming推出自己的解决方案。

考虑这些课程:

// in this example 'delegate' is w1
Object.metaClass.copyExistentialContents = { 
    def newObj = delegate.class.newInstance()

    delegate.properties.each { prop, val ->
        if (prop in ['metaClass','class']) return
        if (val == null) return

        def newVal = val

        if (val instanceof Collection) {
            newVal = val.findAll { it != null }
        } 

        newObj."${prop}" = newVal 
    }

    return newObj
} 

这对解决方案至关重要:

// ---------------- main

def fizz = new Fizz(fizzName: 'fizz')

def buzzes = []
buzzes << new Buzz(buzzName: 'buzz 1')
buzzes << null
buzzes << new Buzz(buzzName: 'buzz 3')

def w1 = new Widget(fizz: fizz, buzzes: buzzes, foos: null)

def w2 = w1.copyExistentialContents()

assert w1.fizz.fizzName == w2.fizz.fizzName
assert null == w2.foos
assert 2 == w2.buzzes.size()
assert 'buzz 1' == w2.buzzes[0].buzzName
assert 'buzz 3' == w2.buzzes[1].buzzName

以下适用于Groovy 2.4.3(所有这些代码都在同一个文件中)。请注意copyExistentialContents方法(从上面):

where