This was spotted by Pierre Sutra from University of Neuchatel:
When a CacheEventFilterConverter is registered with remote event listeners, and running in a cluster, once the CacheEventFilterConverter instance is replicated, the notion that its both a filter AND converter is lost because BaseCacheEntryListenerInvocation's constructor determines that filterAndConvert is false.
The reason this happens is because after clustering it, the ClusterListenerReplicateCallable.call() wraps the filter into an AbstractCacheEventFilterConverter implementation, which does not keep the referential equality that BaseCacheEntryListenerInvocation's constructor checks.
A simple way to avoid this is to implement equals in the AbstractCacheEventFilterConverter implementation and use referential equality. Then, switching BaseCacheEntryListenerInvocation's constructors referential equality by a call to equals is enough to solve the issue.
The reason this bug was detected is because without a fix for it, the filter + converter gets two callbacks instead of one. I've added tests to verify that the number callbacks expected is the correct one.