FilteringStateChangeListenable implements StateChangeListenable<C> { @Override public void registerStateChangeListener(CacheStateChangeListener<? super C> listener) { backingListenable.registerStateChangeListener((old, updated) -> { C oldPlannable = mapAndFilter.apply(old); C updatedPlannable = mapAndFilter.apply(updated); if (oldPlannable != null || updatedPlannable != null) { listener.stateChanged(oldPlannable, updatedPlannable); } }); } FilteringStateChangeListenable(StateChangeListenable<T> backingListenable, Function<? super T, C> mapAndFilter); @Override T registerCustomIndex(T index); @Override void registerStateAddedOrRemovedListener(Consumer<? super C> consumer); @Override void registerStateChangeListener(CacheStateChangeListener<? super C> listener); @Override void registerStateAddedListener(CacheStateAddedListener<? super C> listener); @Override void registerStateRemovedListener(CacheStateRemovedListener<? super C> listener); @Override Stream<C> stream(); @Override UnmodifiableIterator<C> iterator(); @Override void registerAtomicStateChangeListener(AtomicStateChangeListener<? super C> listener); @Override void removeStateChangeListener(CacheStateChangeListener<? super C> listener);  }
@Test void whenOnlyListeningForExtendedStates_thenChangeReceivesAllExtendedStateChanges() { (new FilteringStateChangeListenable<>(cache, this::asExtended)).registerStateChangeListener((old, updated) -> { result = true; resultOld = old; resultUpdated = updated; }); cache.add(state1); assertFalse(result); cache.add(extended1); assertTrue(result); assertNull(resultOld); assertEquals(extended1, resultUpdated); resetResult(); cache.update(state1, state1Updated); assertFalse(result); cache.update(extended1, extended1Updated); assertTrue(result); assertEquals(extended1, resultOld); assertEquals(extended1Updated, resultUpdated); resetResult(); cache.delete(state1Updated.getId()); assertFalse(result); cache.delete(extended1Updated.getId()); assertEquals(extended1Updated, resultOld); assertNull(resultUpdated); }