Description
Recently the number one problem people have been reporting here on Github is an exception that is thrown when trying to compare two arrays. The error message usually looks something like this:
Couldn’t find a differ for type: [java.lang.String
The simple answer is that this is currently not supported. Arrays are a tricky beast. At least when trying to provide a generic solution that is flexible enough to suit everyone. But let me explain, what makes it so hard.
Order matters
There is currently one other issue that becomes more and more pressing the more popular this library gets; and that is List diffing.
java-object-diff supports List diffing, but currently in a rather unexpected way. It simply treats Lists, Sets and other Collection types as Sets. That means:
- No item is expected to be present more than once and if it is, it’s not handled specially.
- Order doesn’t matter and is expected to be handled by the underlying collection.
So it can only detect whether an item has been added, removed or changed, but not whether it has been added a second time or if it changed the position.
That works well enough for many cases, but is obviously not a perfect solution. It’s also the main reason why I did not yet make the jump to a 1.0 release, although the library has ready for production for years (granted the current feature set was sufficient).
But what about Arrays?
To make the jump back to the array problem: from the perspective of the ObjectDiffer an Array is very similar to an ArrayList (who would’ve thought that). It can contain the same object or different versions of that object multiple times in an arbitrary yet delibarate order.
But arrays are even more complicated: there is no add or remove method. Growing or shrinking an array only works by creating a new array with the desired size and copying all elements to their proper index. But it get’s better: in order to actually replace the old array of the target object, the new array needs to be assigned to the field. There are two problems with that:
- The library currently doesn’t access fields, but getters and setters
- What to do when the field is
final
?
There are probably more problems, but these are the ones I’m currently aware of. What I’m trying to say is: the Array issue is much harder to solve, but includes everything that needs to be done for the Collection issue. That’s why the latter one is my number one priority right now.
A solution is in sight
Now don’t worry: I’ve been working on this issue for a while now and I’m close to a pretty good solution. You can see the current state on this branch. Finding the differences was not that hard, once I found and modified a good algorithm. A much bigger problem is the merging part.
Ordered merging of collection items is pretty tricky, when the merging is done one by one on a per-item basis, because in order to insert an item in the right position, you need the surrounding items, to know where that is. But those may have only partially or not at all been merged into the target collection. In order to solve this problem, I may have to rework the entire merge-API of the library.
Because this issue becomes more and more pressing, I’m thinking about finalizing the diffing and leaving out the merging part for now (maybe with an exception or some logging when one tries to use it.)
Although I can promise I’ll work on this feature whenever I can, I must say, that this is currently not very often. Unfortunately it’s also not an easy task to give to willing helpers, that are new to the internals and the design philosophy of the library, because it basically touches every aspect of the API so that the communication overhead would probably be bigger than just doing it alone.
What you can do right now
That sounds pretty discouraging, huh? Don’t worry: there may be some things you can do right now to get what you want. Because I knew this would take a while to get it right, I added some extention points that allow the use of custom differs. So you could write your own ArrayDiffer or ListDiffer that works well for your use-case. Here is a pull request from someone who did just that. You may also get some inspiration from my list-diffing branch.
We may need to make some small adjustents to the library along the way, in case you hit any road blocks. Feel free to report them here in this ticket so we can sort it out.