package fr.openwide.core.jpa.more.business.difference.differ;
import java.util.Collection;
import com.google.common.base.Equivalence;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.base.Predicate;
import de.danielbechler.diff.comparison.ComparisonStrategyResolver;
import de.danielbechler.diff.differ.DifferDispatcher;
import de.danielbechler.diff.filtering.IsReturnableResolver;
import de.danielbechler.diff.node.DiffNode;
import fr.openwide.core.jpa.more.business.difference.differ.strategy.CollectionDifferIndexStrategy;
import fr.openwide.core.jpa.more.business.difference.differ.strategy.CollectionDifferKeyStrategy;
import fr.openwide.core.jpa.more.business.difference.differ.strategy.ItemContentComparisonStrategy;
/**
* An enhanced collection differ that supports fine-tuned settings.
* <p>In particular, this differ allows to define a diff strategy:
* <ul>
* <li>based on an arbitrary predicate on the DiffNode (the strategy is only used if the predicate applies)
* <li>that defines the way two elements (before and after) are considered "equivalent" (and must thus be compared to each other)
* <li>that defines the way a key will be translated to a "human-readable string" (impacts getPath().toString())
* </ul>
* Known bug: node.getPath().toString() will return something like <code>root.property.[itemString]</code> instead of
* <code>root.property[itemString]</code>. This cannot be worked around, as it is built in java-object-diff.
*/
public class ExtendedCollectionDiffer extends AbstractContainerDiffer {
public ExtendedCollectionDiffer(DifferDispatcher differDispatcher,
ComparisonStrategyResolver comparisonStrategyResolver, IsReturnableResolver isReturnableResolver) {
super(
differDispatcher, comparisonStrategyResolver, isReturnableResolver,
new CollectionDifferKeyStrategy<>(
ItemContentComparisonStrategy.deep(),
Functions.identity(), Equivalence.equals(), Functions.toStringFunction()
)
);
}
public <T> ExtendedCollectionDiffer addIndexStrategy(
Predicate<? super DiffNode> predicate) {
addIndexStrategy(predicate, ItemContentComparisonStrategy.deep());
return this;
}
public <T> ExtendedCollectionDiffer addIndexStrategy(
Predicate<? super DiffNode> predicate, ItemContentComparisonStrategy itemContentComparisonStrategy) {
addStrategy(predicate, new CollectionDifferIndexStrategy<>(itemContentComparisonStrategy));
return this;
}
public <T> ExtendedCollectionDiffer addStrategy(
Predicate<? super DiffNode> predicate, Equivalence<? super T> equivalence) {
return addKeyStrategy(predicate, Functions.<T>identity(), equivalence);
}
public <T> ExtendedCollectionDiffer addStrategy(
Predicate<? super DiffNode> predicate, Equivalence<? super T> equivalence, ItemContentComparisonStrategy itemContentComparisonStrategy) {
return addKeyStrategy(predicate, Functions.<T>identity(), equivalence, itemContentComparisonStrategy);
}
public <T, K> ExtendedCollectionDiffer addKeyStrategy(
Predicate<? super DiffNode> predicate,
Function<? super T, ? extends K> keyFunction, Equivalence<? super K> keyEquivalence) {
return addKeyStrategy(predicate, keyFunction, keyEquivalence, ItemContentComparisonStrategy.deep());
}
public <T, K> ExtendedCollectionDiffer addKeyStrategy(
Predicate<? super DiffNode> predicate,
Function<? super T, ? extends K> keyFunction, Equivalence<? super K> keyEquivalence,
ItemContentComparisonStrategy itemContentComparisonStrategy) {
return addKeyStrategy(predicate, keyFunction, keyEquivalence, itemContentComparisonStrategy, Functions.toStringFunction());
}
public <T, K> ExtendedCollectionDiffer addKeyStrategy(
Predicate<? super DiffNode> predicate,
Function<? super T, ? extends K> keyFunction, Equivalence<? super K> keyEquivalence,
ItemContentComparisonStrategy itemContentComparisonStrategy,
Function<? super K, String> toStringFunction) {
addStrategy(predicate, new CollectionDifferKeyStrategy<>(itemContentComparisonStrategy, keyFunction, keyEquivalence, toStringFunction));
return this;
}
@Override
public boolean accepts(Class<?> type) {
return Object[].class.isAssignableFrom(type) || Collection.class.isAssignableFrom(type);
}
}