"Copy Only If Exists Pattern" 在 Groovy 中?
"Copy Only If Exists Pattern" in Groovy?
我有一种情况需要将一个 POJO 实例的内容(属性)复制到另一个相同类型的实例,但仅限于非空 attributes/member 和非空集合。例如:
// 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)
- 对于集合,如果某个特定的element/member为null,则不要复制它,否则,复制它
我觉得有一个 Groovy 的方法可以完成这个,但也许这种“仅当存在时才复制”模式是众所周知的并且已经解决了一些开源库。也许最适合像 Dozer null exclusions 这样的 bean-to-bean 映射实用程序的解决方案(我没有经验)?
我不知道预先存在的功能或库,但您可以使用 metaprogramming 推出自己的解决方案。
考虑这些 类:
class Fizz { def fizzName }
class Buzz { def buzzName }
class Foo { def fooName }
class Widget {
Fizz fizz
List<Buzz> buzzes
List<Foo> foos
}
这对解决方案至关重要:
// 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
}
以下适用于 Groovy 2.4.3(所有这些代码都在同一个文件中)。注意 copyExistentialContents 方法(从上面):
// ---------------- 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
我有一种情况需要将一个 POJO 实例的内容(属性)复制到另一个相同类型的实例,但仅限于非空 attributes/member 和非空集合。例如:
// 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) - 对于集合,如果某个特定的element/member为null,则不要复制它,否则,复制它
我觉得有一个 Groovy 的方法可以完成这个,但也许这种“仅当存在时才复制”模式是众所周知的并且已经解决了一些开源库。也许最适合像 Dozer null exclusions 这样的 bean-to-bean 映射实用程序的解决方案(我没有经验)?
我不知道预先存在的功能或库,但您可以使用 metaprogramming 推出自己的解决方案。
考虑这些 类:
class Fizz { def fizzName }
class Buzz { def buzzName }
class Foo { def fooName }
class Widget {
Fizz fizz
List<Buzz> buzzes
List<Foo> foos
}
这对解决方案至关重要:
// 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
}
以下适用于 Groovy 2.4.3(所有这些代码都在同一个文件中)。注意 copyExistentialContents 方法(从上面):
// ---------------- 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