Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Differences in excluded fields in objects of a collection cause state of collection diff to be changed #216

Open
luispollo opened this issue Jan 25, 2021 · 3 comments

Comments

@luispollo
Copy link

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!

@luispollo
Copy link
Author

luispollo commented Jan 25, 2021

Cc: @robfletcher, @lorin

@luispollo
Copy link
Author

@lorin just pointed out that this may be a duplicate of #96

@syzsh
Copy link

syzsh commented Jun 15, 2022

比较两个集合对象, 会执行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方法, 基于此, 提供两种解决办法:

  1. 可以重写数据类的equalshashCode方法, 忽略添加ExcludedFromDiff注解的字段
  2. 自定义并配置IdentityStrategy

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants