killbill-memoizeit

Details

diff --git a/api/src/main/java/com/ning/billing/invoice/api/InvoiceItem.java b/api/src/main/java/com/ning/billing/invoice/api/InvoiceItem.java
index 10837d6..31c7c03 100644
--- a/api/src/main/java/com/ning/billing/invoice/api/InvoiceItem.java
+++ b/api/src/main/java/com/ning/billing/invoice/api/InvoiceItem.java
@@ -24,7 +24,7 @@ import org.joda.time.LocalDate;
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.util.entity.Entity;
 
-public interface InvoiceItem extends Entity, Comparable<InvoiceItem> {
+public interface InvoiceItem extends Entity {
 
     InvoiceItemType getInvoiceItemType();
 
@@ -61,4 +61,11 @@ public interface InvoiceItem extends Entity, Comparable<InvoiceItem> {
     BigDecimal getRate();
 
     UUID getLinkedItemId();
+
+    /**
+     * Items match if they correspond to the same subscription for the same catalog plan and same start / end dates
+     *
+     * @return true if current and other items match
+     */
+    boolean matches(Object other);
 }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/generator/DefaultInvoiceGenerator.java b/invoice/src/main/java/com/ning/billing/invoice/generator/DefaultInvoiceGenerator.java
index 9850f7d..1c9a78a 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/generator/DefaultInvoiceGenerator.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/generator/DefaultInvoiceGenerator.java
@@ -128,7 +128,7 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
         // Finally add thos new items on the new invoice
         invoice.addInvoiceItems(proposedItems);
 
-        return invoice;
+        return proposedItems.size() != 0 ?  invoice : null;
     }
 
     void generateCBAForExistingInvoices(final UUID accountId, final List<Invoice> existingInvoices,
@@ -259,7 +259,6 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
                 maxDate = invoice.getTargetDate();
             }
         }
-
         return maxDate;
     }
 
@@ -276,7 +275,7 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
             final Iterator<InvoiceItem> existingItemIterator = existingInvoiceItems.iterator();
             while (existingItemIterator.hasNext()) {
                 final InvoiceItem existingItem = existingItemIterator.next();
-                if (existingItem.equals(proposedItem)) {
+                if (existingItem.matches(proposedItem)) {
                     existingItemIterator.remove();
                     proposedItemIterator.remove();
                     break;
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/AdjInvoiceItem.java b/invoice/src/main/java/com/ning/billing/invoice/model/AdjInvoiceItem.java
index 0675567..0255203 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/AdjInvoiceItem.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/AdjInvoiceItem.java
@@ -40,56 +40,6 @@ public abstract class AdjInvoiceItem extends InvoiceItemBase {
         super(id, createdDate, invoiceId, accountId, null, null, null, null, startDate, endDate, amount, currency, reversingId);
     }
 
-    @Override
-    public boolean equals(final Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-        final AdjInvoiceItem that = (AdjInvoiceItem) o;
-        return this.compareTo(that) == 0;
-    }
-
-    @Override
-    public int hashCode() {
-        int result = accountId.hashCode();
-        result = 31 * result + invoiceId.hashCode();
-        result = 31 * result + startDate.hashCode();
-        result = 31 * result + amount.hashCode();
-        result = 31 * result + currency.hashCode();
-        result = 31 * result + getInvoiceItemType().hashCode();
-        result = 31 * result + getId().hashCode();
-        return result;
-    }
-
-    @Override
-    public int compareTo(final InvoiceItem item) {
-
-        if (!(item instanceof AdjInvoiceItem)) {
-            return 1;
-        }
-
-        final AdjInvoiceItem that = (AdjInvoiceItem) item;
-
-        if (accountId.compareTo(that.accountId) != 0) {
-            return accountId.compareTo(that.accountId);
-        }
-        if (invoiceId.compareTo(that.invoiceId) != 0) {
-            return invoiceId.compareTo(that.invoiceId);
-        }
-        if (amount.compareTo(that.amount) != 0) {
-            return amount.compareTo(that.amount);
-        }
-        if (startDate.compareTo(that.startDate) != 0) {
-            return startDate.compareTo(that.startDate);
-        }
-        if (currency != that.currency) {
-            return currency.ordinal() > that.currency.ordinal() ? 1 : -1;
-        }
-        return id.compareTo(that.getId());
-    }
 
     @Override
     public abstract InvoiceItemType getInvoiceItemType();
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/ExternalChargeInvoiceItem.java b/invoice/src/main/java/com/ning/billing/invoice/model/ExternalChargeInvoiceItem.java
index c9afc1a..a836247 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/ExternalChargeInvoiceItem.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/ExternalChargeInvoiceItem.java
@@ -55,76 +55,6 @@ public class ExternalChargeInvoiceItem extends InvoiceItemBase {
     }
 
     @Override
-    public int hashCode() {
-        int result = accountId.hashCode();
-        result = 31 * result + (subscriptionId != null ? subscriptionId.hashCode() : 0);
-        result = 31 * result + (bundleId != null ? bundleId.hashCode() : 0);
-        result = 31 * result + (planName != null ? planName.hashCode() : 0);
-        result = 31 * result + (phaseName != null ? phaseName.hashCode() : 0);
-        result = 31 * result + (startDate != null ? startDate.hashCode() : 0);
-        result = 31 * result + (endDate != null ? endDate.hashCode() : 0);
-        result = 31 * result + amount.hashCode();
-        result = 31 * result + currency.hashCode();
-        return result;
-    }
-
-    @Override
-    public int compareTo(final InvoiceItem item) {
-        if (!(item instanceof ExternalChargeInvoiceItem)) {
-            return 1;
-        }
-
-        final ExternalChargeInvoiceItem that = (ExternalChargeInvoiceItem) item;
-        final int compareAccounts = getAccountId().compareTo(that.getAccountId());
-        if (compareAccounts == 0) {
-            return getStartDate().compareTo(that.getStartDate());
-        } else {
-            return compareAccounts;
-        }
-    }
-
-    @Override
-    public boolean equals(final Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-
-        final ExternalChargeInvoiceItem that = (ExternalChargeInvoiceItem) o;
-        if (accountId.compareTo(that.accountId) != 0) {
-            return false;
-        }
-        if (subscriptionId != null ? !subscriptionId.equals(that.subscriptionId) : that.subscriptionId != null) {
-            return false;
-        }
-        if (bundleId != null ? !bundleId.equals(that.bundleId) : that.bundleId != null) {
-            return false;
-        }
-        if (amount != null ? amount.compareTo(that.amount) != 0 : that.amount != null) {
-            return false;
-        }
-        if (currency != that.currency) {
-            return false;
-        }
-        if (startDate != null ? startDate.compareTo(that.startDate) != 0 : that.startDate != null) {
-            return false;
-        }
-        if (endDate != null ? endDate.compareTo(that.endDate) != 0 : that.endDate != null) {
-            return false;
-        }
-        if (phaseName != null ? !phaseName.equals(that.phaseName) : that.phaseName != null) {
-            return false;
-        }
-        if (planName != null ? !planName.equals(that.planName) : that.planName != null) {
-            return false;
-        }
-
-        return true;
-    }
-
-    @Override
     public InvoiceItemType getInvoiceItemType() {
         return InvoiceItemType.EXTERNAL_CHARGE;
     }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/FixedPriceInvoiceItem.java b/invoice/src/main/java/com/ning/billing/invoice/model/FixedPriceInvoiceItem.java
index 6fba12a..c17fd2b 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/FixedPriceInvoiceItem.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/FixedPriceInvoiceItem.java
@@ -56,86 +56,6 @@ public class FixedPriceInvoiceItem extends InvoiceItemBase {
     }
 
     @Override
-    public int hashCode() {
-        int result = accountId.hashCode();
-        result = 31 * result + (subscriptionId != null ? subscriptionId.hashCode() : 0);
-        result = 31 * result + (bundleId != null ? bundleId.hashCode() : 0);
-        result = 31 * result + (planName != null ? planName.hashCode() : 0);
-        result = 31 * result + (phaseName != null ? phaseName.hashCode() : 0);
-        result = 31 * result + (startDate != null ? startDate.hashCode() : 0);
-        result = 31 * result + (endDate != null ? endDate.hashCode() : 0);
-        result = 31 * result + amount.hashCode();
-        result = 31 * result + currency.hashCode();
-        return result;
-    }
-
-    @Override
-    public int compareTo(final InvoiceItem item) {
-        if (!(item instanceof FixedPriceInvoiceItem)) {
-            return 1;
-        }
-
-        final FixedPriceInvoiceItem that = (FixedPriceInvoiceItem) item;
-        final int compareAccounts = getAccountId().compareTo(that.getAccountId());
-        if (compareAccounts == 0 && bundleId != null) {
-            final int compareBundles = getBundleId().compareTo(that.getBundleId());
-            if (compareBundles == 0 && subscriptionId != null) {
-                final int compareSubscriptions = getSubscriptionId().compareTo(that.getSubscriptionId());
-                if (compareSubscriptions == 0) {
-                    return getStartDate().compareTo(that.getStartDate());
-                } else {
-                    return compareSubscriptions;
-                }
-            } else {
-                return compareBundles;
-            }
-        } else {
-            return compareAccounts;
-        }
-    }
-
-    @Override
-    public boolean equals(final Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-
-        final FixedPriceInvoiceItem that = (FixedPriceInvoiceItem) o;
-        if (accountId.compareTo(that.accountId) != 0) {
-            return false;
-        }
-        if (subscriptionId != null ? !subscriptionId.equals(that.subscriptionId) : that.subscriptionId != null) {
-            return false;
-        }
-        if (bundleId != null ? !bundleId.equals(that.bundleId) : that.bundleId != null) {
-            return false;
-        }
-        if (amount != null ? amount.compareTo(that.amount) != 0 : that.amount != null) {
-            return false;
-        }
-        if (currency != that.currency) {
-            return false;
-        }
-        if (startDate != null ? startDate.compareTo(that.startDate) != 0 : that.startDate != null) {
-            return false;
-        }
-        if (endDate != null ? endDate.compareTo(that.endDate) != 0 : that.endDate != null) {
-            return false;
-        }
-        if (phaseName != null ? !phaseName.equals(that.phaseName) : that.phaseName != null) {
-            return false;
-        }
-        if (planName != null ? !planName.equals(that.planName) : that.planName != null) {
-            return false;
-        }
-
-        return true;
-    }
-
-    @Override
     public InvoiceItemType getInvoiceItemType() {
         return InvoiceItemType.FIXED;
     }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceItemBase.java b/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceItemBase.java
index 9eeb8d9..5a27a42 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceItemBase.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceItemBase.java
@@ -170,13 +170,94 @@ public abstract class InvoiceItemBase extends EntityBase implements InvoiceItem 
         return linkedItemId;
     }
 
+
     @Override
-    public abstract InvoiceItemType getInvoiceItemType();
+    public boolean equals(final Object o) {
+
+        if (!matches(o)) {
+            return false;
+        }
+        final InvoiceItemBase that = (InvoiceItemBase) o;
+        if (!super.equals(that)) {
+            return false;
+        }
+        if (invoiceId != null ? !invoiceId.equals(that.invoiceId) : that.invoiceId != null) {
+            return false;
+        }
+        if (linkedItemId != null ? !linkedItemId.equals(that.linkedItemId) : that.linkedItemId != null) {
+            return false;
+        }
+        return true;
+    }
+
 
     @Override
-    public abstract String getDescription();
+    public boolean matches(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof InvoiceItemBase)) {
+            return false;
+        }
+
+        final InvoiceItemBase that = (InvoiceItemBase) o;
+
+        if (accountId != null ? !accountId.equals(that.accountId) : that.accountId != null) {
+            return false;
+        }
+        if (bundleId != null ? !bundleId.equals(that.bundleId) : that.bundleId != null) {
+            return false;
+        }
+        if (subscriptionId != null ? !subscriptionId.equals(that.subscriptionId) : that.subscriptionId != null) {
+            return false;
+        }
+        if (safeCompareTo(startDate, that.startDate) != 0) {
+            return false;
+        }
+        if (safeCompareTo(endDate, that.endDate) != 0) {
+            return false;
+        }
+        if (safeCompareTo(amount, that.amount) != 0) {
+            return false;
+        }
+        if (safeCompareTo(rate, that.rate) != 0) {
+            return false;
+        }
+        if (currency != that.currency) {
+            return false;
+        }
+        if (phaseName != null ? !phaseName.equals(that.phaseName) : that.phaseName != null) {
+            return false;
+        }
+        if (planName != null ? !planName.equals(that.planName) : that.planName != null) {
+            return false;
+        }
+        return true;
+    }
+
+
+    @Override
+    public int hashCode() {
+        int result = super.hashCode();
+        result = 31 * result + (invoiceId != null ? invoiceId.hashCode() : 0);
+        result = 31 * result + (accountId != null ? accountId.hashCode() : 0);
+        result = 31 * result + (startDate != null ? startDate.hashCode() : 0);
+        result = 31 * result + (endDate != null ? endDate.hashCode() : 0);
+        result = 31 * result + (amount != null ? amount.hashCode() : 0);
+        result = 31 * result + (currency != null ? currency.hashCode() : 0);
+        result = 31 * result + (subscriptionId != null ? subscriptionId.hashCode() : 0);
+        result = 31 * result + (bundleId != null ? bundleId.hashCode() : 0);
+        result = 31 * result + (planName != null ? planName.hashCode() : 0);
+        result = 31 * result + (phaseName != null ? phaseName.hashCode() : 0);
+        result = 31 * result + (rate != null ? rate.hashCode() : 0);
+        result = 31 * result + (linkedItemId != null ? linkedItemId.hashCode() : 0);
+        return result;
+    }
 
     @Override
-    public abstract int compareTo(InvoiceItem invoiceItem);
+    public abstract InvoiceItemType getInvoiceItemType();
+
+    @Override
+    public abstract String getDescription();
 
 }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/RecurringInvoiceItem.java b/invoice/src/main/java/com/ning/billing/invoice/model/RecurringInvoiceItem.java
index e27050e..7c8475d 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/RecurringInvoiceItem.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/RecurringInvoiceItem.java
@@ -53,106 +53,6 @@ public class RecurringInvoiceItem extends InvoiceItemBase {
     }
 
     @Override
-    public int compareTo(final InvoiceItem item) {
-        if (item == null) {
-            return -1;
-        }
-        if (!(item instanceof RecurringInvoiceItem)) {
-            return -1;
-        }
-
-        final RecurringInvoiceItem that = (RecurringInvoiceItem) item;
-        final int compareAccounts = getAccountId().compareTo(that.getAccountId());
-        if (compareAccounts == 0 && bundleId != null) {
-            final int compareBundles = getBundleId().compareTo(that.getBundleId());
-            if (compareBundles == 0 && subscriptionId != null) {
-
-                final int compareSubscriptions = getSubscriptionId().compareTo(that.getSubscriptionId());
-                if (compareSubscriptions == 0) {
-                    final int compareStartDates = getStartDate().compareTo(that.getStartDate());
-                    if (compareStartDates == 0) {
-                        return getEndDate().compareTo(that.getEndDate());
-                    } else {
-                        return compareStartDates;
-                    }
-                } else {
-                    return compareSubscriptions;
-                }
-            } else {
-                return compareBundles;
-            }
-        } else {
-            return compareAccounts;
-        }
-    }
-
-    @Override
-    public boolean equals(final Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-
-        final RecurringInvoiceItem that = (RecurringInvoiceItem) o;
-
-        // do not include invoice item type, since a reversing item can be equal to the original item
-        if (accountId.compareTo(that.accountId) != 0) {
-            return false;
-        }
-        if (amount.compareTo(that.amount) != 0) {
-            return false;
-        }
-        if (currency != that.currency) {
-            return false;
-        }
-        if (startDate.compareTo(that.startDate) != 0) {
-            return false;
-        }
-        if (endDate.compareTo(that.endDate) != 0) {
-            return false;
-        }
-        if (!phaseName.equals(that.phaseName)) {
-            return false;
-        }
-        if (!planName.equals(that.planName)) {
-            return false;
-        }
-        if (rate.compareTo(that.rate) != 0) {
-            return false;
-        }
-        if (linkedItemId != null ? !linkedItemId.equals(that.linkedItemId) : that.linkedItemId != null) {
-            return false;
-        }
-        if (subscriptionId != null ? !subscriptionId.equals(that.subscriptionId) : that.subscriptionId != null) {
-            return false;
-        }
-        if (bundleId != null ? !bundleId.equals(that.bundleId) : that.bundleId != null) {
-            return false;
-        }
-
-        return true;
-    }
-
-    @Override
-    public int hashCode() {
-        int result = accountId.hashCode();
-        result = 31 * result + (subscriptionId != null ? subscriptionId.hashCode() : 0);
-        result = 31 * result + (bundleId != null ? bundleId.hashCode() : 0);
-        result = 31 * result + planName.hashCode();
-        result = 31 * result + phaseName.hashCode();
-        result = 31 * result + startDate.hashCode();
-        result = 31 * result + endDate.hashCode();
-        result = 31 * result + amount.hashCode();
-        result = 31 * result + rate.hashCode();
-        result = 31 * result + currency.hashCode();
-        result = 31 * result + getInvoiceItemType().hashCode();
-        result = 31 * result + (linkedItemId != null ? linkedItemId.hashCode() : 0);
-        return result;
-    }
-
-    @Override
     public InvoiceItemType getInvoiceItemType() {
         return InvoiceItemType.RECURRING;
     }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java b/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java
index fa371f3..e199843 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java
@@ -135,11 +135,6 @@ public class DefaultInvoiceItemFormatter implements InvoiceItemFormatter {
     }
 
     @Override
-    public int compareTo(final InvoiceItem invoiceItem) {
-        return item.compareTo(invoiceItem);
-    }
-
-    @Override
     public UUID getId() {
         return item.getId();
     }
@@ -163,4 +158,9 @@ public class DefaultInvoiceItemFormatter implements InvoiceItemFormatter {
     public UUID getLinkedItemId() {
         return null;
     }
+
+    @Override
+    public boolean matches(final Object other) {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/TestInvoiceItemDao.java b/invoice/src/test/java/com/ning/billing/invoice/dao/TestInvoiceItemDao.java
index 2ebd1ba..f788894 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/TestInvoiceItemDao.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/TestInvoiceItemDao.java
@@ -21,6 +21,7 @@ import java.util.List;
 import java.util.UUID;
 
 import org.joda.time.LocalDate;
+import org.testng.Assert;
 import org.testng.annotations.Test;
 
 import com.ning.billing.catalog.api.Currency;
@@ -146,7 +147,7 @@ public class TestInvoiceItemDao extends InvoiceTestSuiteWithEmbeddedDB {
         invoiceUtil.createInvoiceItem(creditInvoiceItem, internalCallContext);
 
         final InvoiceItemModelDao savedItem = invoiceUtil.getInvoiceItemById(creditInvoiceItem.getId(), internalCallContext);
-        assertEquals(InvoiceItemFactory.fromModelDao(savedItem), creditInvoiceItem);
+        assertSameInvoiceItem(creditInvoiceItem, savedItem);
     }
 
     @Test(groups = "slow")
@@ -160,7 +161,7 @@ public class TestInvoiceItemDao extends InvoiceTestSuiteWithEmbeddedDB {
         invoiceUtil.createInvoiceItem(fixedPriceInvoiceItem, internalCallContext);
 
         final InvoiceItemModelDao savedItem = invoiceUtil.getInvoiceItemById(fixedPriceInvoiceItem.getId(), internalCallContext);
-        assertEquals(InvoiceItemFactory.fromModelDao(savedItem), fixedPriceInvoiceItem);
+        assertSameInvoiceItem(fixedPriceInvoiceItem, savedItem);
     }
 
     @Test(groups = "slow")
@@ -175,6 +176,14 @@ public class TestInvoiceItemDao extends InvoiceTestSuiteWithEmbeddedDB {
         invoiceUtil.createInvoiceItem(externalChargeInvoiceItem, internalCallContext);
 
         final InvoiceItemModelDao savedItem = invoiceUtil.getInvoiceItemById(externalChargeInvoiceItem.getId(), internalCallContext);
-        assertEquals(InvoiceItemFactory.fromModelDao(savedItem), externalChargeInvoiceItem);
+        assertSameInvoiceItem(externalChargeInvoiceItem, savedItem);
+    }
+
+
+    private void assertSameInvoiceItem(final InvoiceItem initialItem, final InvoiceItemModelDao fromDao) {
+        final InvoiceItem newItem = InvoiceItemFactory.fromModelDao(fromDao);
+        Assert.assertEquals(newItem.getId(), initialItem.getId());
+        Assert.assertTrue(newItem.matches(initialItem));
+
     }
 }
diff --git a/invoice/src/test/java/com/ning/billing/invoice/model/TestExternalChargeInvoiceItem.java b/invoice/src/test/java/com/ning/billing/invoice/model/TestExternalChargeInvoiceItem.java
index 7eba185..2865b3f 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/model/TestExternalChargeInvoiceItem.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/model/TestExternalChargeInvoiceItem.java
@@ -64,9 +64,9 @@ public class TestExternalChargeInvoiceItem extends InvoiceTestSuiteNoDB {
         // Check comparison (done by start date)
         final ExternalChargeInvoiceItem itemBefore = new ExternalChargeInvoiceItem(id, invoiceId, accountId, bundleId, description,
                                                                                    effectiveDate.minusDays(1), amount, currency);
-        Assert.assertEquals(itemBefore.compareTo(item), -1);
+        Assert.assertFalse(itemBefore.matches(item));
         final ExternalChargeInvoiceItem itemAfter = new ExternalChargeInvoiceItem(id, invoiceId, accountId, bundleId, description,
                                                                                   effectiveDate.plusDays(1), amount, currency);
-        Assert.assertEquals(itemAfter.compareTo(item), 1);
+        Assert.assertFalse(itemAfter.matches(item));
     }
 }
diff --git a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/BusinessInvoiceDao.java b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/BusinessInvoiceDao.java
index 4b8d05c..d407bd6 100644
--- a/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/BusinessInvoiceDao.java
+++ b/osgi-bundles/bundles/analytics/src/main/java/com/ning/billing/osgi/bundles/analytics/dao/BusinessInvoiceDao.java
@@ -485,8 +485,8 @@ public class BusinessInvoiceDao extends BusinessAnalyticsDaoBase {
         }
 
         @Override
-        public int compareTo(final InvoiceItem o) {
-            return repairInvoiceItem.compareTo(o);
+        public boolean matches(final Object other) {
+            throw new UnsupportedOperationException();
         }
 
         @Override
diff --git a/payment/src/test/java/com/ning/billing/payment/MockRecurringInvoiceItem.java b/payment/src/test/java/com/ning/billing/payment/MockRecurringInvoiceItem.java
index 70736a5..a797105 100644
--- a/payment/src/test/java/com/ning/billing/payment/MockRecurringInvoiceItem.java
+++ b/payment/src/test/java/com/ning/billing/payment/MockRecurringInvoiceItem.java
@@ -164,6 +164,11 @@ public class MockRecurringInvoiceItem extends EntityBase implements InvoiceItem 
         return reversedItemId;
     }
 
+    @Override
+    public boolean matches(final Object other) {
+        throw new UnsupportedOperationException();
+    }
+
     public boolean reversesItem() {
         return (reversedItemId != null);
     }
@@ -173,103 +178,6 @@ public class MockRecurringInvoiceItem extends EntityBase implements InvoiceItem 
         return rate;
     }
 
-    @Override
-    public int compareTo(final InvoiceItem item) {
-        if (item == null) {
-            return -1;
-        }
-        if (!(item instanceof MockRecurringInvoiceItem)) {
-            return -1;
-        }
-
-        final MockRecurringInvoiceItem that = (MockRecurringInvoiceItem) item;
-        final int compareAccounts = getAccountId().compareTo(that.getAccountId());
-        if (compareAccounts == 0 && bundleId != null) {
-            final int compareBundles = getBundleId().compareTo(that.getBundleId());
-            if (compareBundles == 0 && subscriptionId != null) {
-
-                final int compareSubscriptions = getSubscriptionId().compareTo(that.getSubscriptionId());
-                if (compareSubscriptions == 0) {
-                    final int compareStartDates = getStartDate().compareTo(that.getStartDate());
-                    if (compareStartDates == 0) {
-                        return getEndDate().compareTo(that.getEndDate());
-                    } else {
-                        return compareStartDates;
-                    }
-                } else {
-                    return compareSubscriptions;
-                }
-            } else {
-                return compareBundles;
-            }
-        } else {
-            return compareAccounts;
-        }
-    }
-
-    @Override
-    public boolean equals(final Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-
-        final MockRecurringInvoiceItem that = (MockRecurringInvoiceItem) o;
-
-        if (accountId.compareTo(that.accountId) != 0) {
-            return false;
-        }
-        if (amount.compareTo(that.amount) != 0) {
-            return false;
-        }
-        if (currency != that.currency) {
-            return false;
-        }
-        if (startDate.compareTo(that.startDate) != 0) {
-            return false;
-        }
-        if (endDate.compareTo(that.endDate) != 0) {
-            return false;
-        }
-        if (!phaseName.equals(that.phaseName)) {
-            return false;
-        }
-        if (!planName.equals(that.planName)) {
-            return false;
-        }
-        if (rate.compareTo(that.rate) != 0) {
-            return false;
-        }
-        if (reversedItemId != null ? !reversedItemId.equals(that.reversedItemId) : that.reversedItemId != null) {
-            return false;
-        }
-        if (subscriptionId != null ? !subscriptionId.equals(that.subscriptionId) : that.subscriptionId != null) {
-            return false;
-        }
-        if (bundleId != null ? !bundleId.equals(that.bundleId) : that.bundleId != null) {
-            return false;
-        }
-
-        return true;
-    }
-
-    @Override
-    public int hashCode() {
-        int result = accountId.hashCode();
-        result = 31 * result + (subscriptionId != null ? subscriptionId.hashCode() : 0);
-        result = 31 * result + (bundleId != null ? bundleId.hashCode() : 0);
-        result = 31 * result + planName.hashCode();
-        result = 31 * result + phaseName.hashCode();
-        result = 31 * result + startDate.hashCode();
-        result = 31 * result + endDate.hashCode();
-        result = 31 * result + amount.hashCode();
-        result = 31 * result + rate.hashCode();
-        result = 31 * result + currency.hashCode();
-        result = 31 * result + (reversedItemId != null ? reversedItemId.hashCode() : 0);
-        return result;
-    }
 
     @Override
     public String toString() {
diff --git a/util/src/main/java/com/ning/billing/util/entity/EntityBase.java b/util/src/main/java/com/ning/billing/util/entity/EntityBase.java
index 628a078..c188beb 100644
--- a/util/src/main/java/com/ning/billing/util/entity/EntityBase.java
+++ b/util/src/main/java/com/ning/billing/util/entity/EntityBase.java
@@ -19,6 +19,8 @@ package com.ning.billing.util.entity;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
+import org.joda.time.ReadableInstant;
+import org.joda.time.ReadablePartial;
 
 public abstract class EntityBase implements Entity {
 
@@ -73,11 +75,10 @@ public abstract class EntityBase implements Entity {
         }
 
         final EntityBase that = (EntityBase) o;
-
-        if (createdDate != null ? !createdDate.equals(that.createdDate) : that.createdDate != null) {
+        if (id != null ? !id.equals(that.id) : that.id != null) {
             return false;
         }
-        if (id != null ? !id.equals(that.id) : that.id != null) {
+        if (createdDate != null ? !createdDate.equals(that.createdDate) : that.createdDate != null) {
             return false;
         }
         if (updatedDate != null ? !updatedDate.equals(that.updatedDate) : that.updatedDate != null) {
@@ -94,4 +95,16 @@ public abstract class EntityBase implements Entity {
         result = 31 * result + (updatedDate != null ? updatedDate.hashCode() : 0);
         return result;
     }
+
+    protected <T> int safeCompareTo(final Comparable<T> c1, final T c2) {
+        if (c1 == null && c2 == null) {
+            return 0;
+        } else if (c1 == null) {
+            return -1;
+        } else if (c2 == null) {
+            return 1;
+        } else {
+            return c1.compareTo(c2);
+        }
+    }
 }