package fr.openwide.core.jpa.more.business.difference.access; import java.util.Arrays; import java.util.Collection; import com.google.common.base.Equivalence; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import de.danielbechler.diff.access.Accessor; import de.danielbechler.diff.selector.ElementSelector; import fr.openwide.core.jpa.more.business.difference.selector.CollectionItemByKeySelector; public class CollectionItemByKeyAccessor<T, K> implements Accessor, IKeyAwareAccessor<K> { private final K reference; private final Function<? super T, ? extends K> keyFunction; private final Equivalence<? super K> equivalence; private final Predicate<? super T> predicate; private final String humanReadableString; public CollectionItemByKeyAccessor( K reference, Function<? super T, ? extends K> keyFunction, Equivalence<? super K> equivalence, String humanReadableString) { this.reference = reference; this.keyFunction = keyFunction; this.equivalence = equivalence; this.predicate = Predicates.compose(equivalence.equivalentTo(reference), keyFunction); this.humanReadableString = "[" + humanReadableString + "]"; } @Override public K getKey() { return reference; } @SuppressWarnings("unchecked") private static <T> Collection<T> objectAsCollection(final Object object) { if (object == null) { return null; // NOSONAR: we can't return an empty collection, since we don't know which subtype (List, Set, ...) is expected. } else if (object instanceof Collection) { return (Collection<T>) object; } else if (object instanceof Object[]) { return Arrays.asList((T[]) object); } throw new IllegalArgumentException(object.getClass().toString()); } @Override public ElementSelector getElementSelector() { return new CollectionItemByKeySelector<>(keyFunction, equivalence, reference, humanReadableString); } @Override public void set(final Object target, final Object value) { throw new UnsupportedOperationException("Cannot set value on collection/array items."); } @Override public Object get(final Object target) { final Collection<T> targetCollection = objectAsCollection(target); if (targetCollection == null) { return null; } for (final T item : targetCollection) { if (item != null && predicate.apply(item)) { return item; } } return null; } @Override public void unset(final Object target) { throw new UnsupportedOperationException("Cannot unset value on collection/array items."); } @Override public String toString() { return "collection/array item " + getElementSelector(); } }