java-object-diff
java-object-diff copied to clipboard
Differences in excluded fields in objects of a collection cause state of collection diff to be changed
Hi Daniel,
First of all, thanks a lot for the awesome library! We've been using it in open-source Spinnaker for over a year now with great results.
I think I may have run into a corner case. We are configuring a differ in Kotlin like so:
val differ: ObjectDiffer = ObjectDifferBuilder
.startBuilding()
.apply {
comparison().ofType(Instant::class.java).toUseEqualsMethod()
inclusion().resolveUsing(object : InclusionResolver {
override fun getInclusion(node: DiffNode): Inclusion =
if (node.getPropertyAnnotation<ExcludedFromDiff>() != null) EXCLUDED else INCLUDED
override fun enablesStrictIncludeMode() = false
})
}
.build()
This allows us to use a @ExcludedFromDiff
annotation to exclude unwanted properties from the diff. This normally works just fine, but I came across a case where, if the objects with excluded fields are part of a collection, and I compare the collection itself, the differ reports a state of CHANGED
instead of the expected UNTOUCHED
.
For example, this comparison reports UNTOUCHED
:
data class MyObject(
@get:ExcludedFromDiff
val prop: String
)
val base = MyObject("test")
differ.compare(base, base.copy(prop = "whatever"))
But this comparison reports CHANGED
:
differ.compare(setOf(base), setOf(base.copy(prop = "whatever")))
I've tried my best to debug the issue, but failed. If you have any insights and could at least confirm whether you think this might be a bug and whether there's any workaround in version 0.95, that would be greatly appreciated!
Cc: @robfletcher, @lorin
@lorin just pointed out that this may be a duplicate of https://github.com/SQiShER/java-object-diff/issues/96
比较两个集合对象, 会执行de.danielbechler.diff.differ.CollectionDiffer
比较器逻辑:
- 遍历working集合中的每个元素, 如果不存在于base集合中, 则认为working集合新增了元素
- 遍历base集合中的每个元素, 如果不存在于working集合中, 则认为working集合删除了元素
- 元素同时存在于两个集合中, 才会继续比较每个属性的值, 这种情况你的配置才会生效
关键代码:
de.danielbechler.diff.differ.CollectionDiffer#compareInternally de.danielbechler.diff.access.CollectionItemAccessor#get de.danielbechler.diff.identity.EqualsIdentityStrategy#equals
判断集合中元素是否相同, 默认调用对象的equals
方法, 基于此, 提供两种解决办法:
- 可以重写数据类的
equals
和hashCode
方法, 忽略添加ExcludedFromDiff
注解的字段 - 自定义并配置
IdentityStrategy