package fr.openwide.core.jpa.business.generic.util; import java.io.Serializable; import java.util.Comparator; import org.springframework.util.Assert; import com.google.common.collect.Ordering; import fr.openwide.core.commons.util.ordering.AbstractNullSafeComparator; import fr.openwide.core.jpa.business.generic.model.GenericEntity; /** * A {@link GenericEntity} comparator that compares IDs. * <p>The {@link #AbstractGenericEntityComparator() default implementation} mimics the behavior of {@link GenericEntity#compareTo(GenericEntity)}, * except that it is null-safe. It assumes a null entity is <em>more</em> * than a non-null one, and that an entity with a null ID is <em>more</em> than an entity with a non-null ID. This behavior is consistent with * {@link GenericEntity#isNew()} and {@link GenericEntity#compareTo(GenericEntity)}: an entity without an id is new, hence more recent than an entity with an id, which is not new. * <p>This comparator is consistent with equals as long as the {@link #equalsNotNullObjects(GenericEntity, GenericEntity)} method is not overridden. * <p><strong>WARNING:</strong> trying to compare two not-null entities with null IDs which are different according to * {@link #equalsNotNullObjects(GenericEntity, GenericEntity)} will result in an {@link IllegalArgumentException} * being thrown, since such objects are inherently incomparable. This behavior may be overridden in subclasses by * comparing other attributes of the entity. */ public abstract class AbstractGenericEntityComparator<K extends Comparable<K> & Serializable, E extends GenericEntity<K,?>> extends AbstractNullSafeComparator<E> { private static final long serialVersionUID = -5933751018161012653L; private final Comparator<? super K> keyComparator; public AbstractGenericEntityComparator() { this(false, Ordering.natural().nullsLast()); } /** * @param nullIsLow Whether a null entity is lower than a non-null entity. This only applies to the entity object, not to its id. * @param keyComparator The {@link GenericEntity#getId() key} comparator. * Must be null-safe in order for this comparator to be null-safe. * Must be serializable in order for this comparator to be serializable. */ public AbstractGenericEntityComparator(boolean nullIsLow, Comparator<? super K> keyComparator) { super(nullIsLow); Assert.notNull(keyComparator); this.keyComparator = keyComparator; } @Override protected boolean equalsNotNullObjects(E left, E right) { return left.equals(right); } /** * @throws IllegalArgumentException if these entities may not be compared, i.e. they are different, but their respective IDs are null and there is no other way to compare them. */ @Override protected int compareNotNullObjects(E left, E right) { K leftId = left.getId(); K rightId = right.getId(); if (leftId == null && rightId == null) { throw new IllegalArgumentException("Cannot compare two different entities with null IDs"); } return keyComparator.compare(leftId, rightId); } }