From 98660bef8667d75a798b67f073703cd9ec051e9c Mon Sep 17 00:00:00 2001
From: "Brian S. O'Neill" <bronee@gmail.com>
Date: Thu, 24 May 2007 21:15:41 +0000
Subject: Fix bug which would throw spurious IllegalArgumentException from
 StorableGenerator.

---
 .../amazon/carbonado/gen/StorableGenerator.java    |  9 ++---
 .../com/amazon/carbonado/info/ChainedProperty.java | 41 +++++++++++++++++-----
 2 files changed, 37 insertions(+), 13 deletions(-)

diff --git a/src/main/java/com/amazon/carbonado/gen/StorableGenerator.java b/src/main/java/com/amazon/carbonado/gen/StorableGenerator.java
index 0fa8708..5f473cb 100644
--- a/src/main/java/com/amazon/carbonado/gen/StorableGenerator.java
+++ b/src/main/java/com/amazon/carbonado/gen/StorableGenerator.java
@@ -1885,7 +1885,7 @@ public final class StorableGenerator<S extends Storable> {
             addAltKeyMethods:
             for (int i=0; i<mInfo.getAlternateKeyCount(); i++) {
                 Map<String, StorableProperty<S>> altProps =
-                    new HashMap<String, StorableProperty<S>>();
+                    new LinkedHashMap<String, StorableProperty<S>>();
 
                 StorableKey<S> altKey = mInfo.getAlternateKey(i);
 
@@ -1905,7 +1905,7 @@ public final class StorableGenerator<S extends Storable> {
             // Define protected isRequiredDataInitialized method.
             defineIsRequiredDataInitialized: {
                 Map<String, StorableProperty<S>> requiredProperties =
-                    new HashMap<String, StorableProperty<S>>();
+                    new LinkedHashMap<String, StorableProperty<S>>();
 
                 for (StorableProperty property : mAllProperties.values()) {
                     if (!property.isDerived() &&
@@ -2686,7 +2686,7 @@ public final class StorableGenerator<S extends Storable> {
         b.returnValue(TypeDesc.BOOLEAN);
     }
 
-    private int findPropertyOrdinal(StorableProperty property) {
+    private int findPropertyOrdinal(StorableProperty<S> property) {
         int ordinal = 0;
         for (StorableProperty<S> p : mAllProperties.values()) {
             if (p == property) {
@@ -2694,7 +2694,8 @@ public final class StorableGenerator<S extends Storable> {
             }
             ordinal++;
         }
-        throw new IllegalArgumentException();
+        throw new IllegalArgumentException
+            ("Unable to find property " + property + " in " + mAllProperties);
     }
 
     /**
diff --git a/src/main/java/com/amazon/carbonado/info/ChainedProperty.java b/src/main/java/com/amazon/carbonado/info/ChainedProperty.java
index d5b41a8..0299ae8 100644
--- a/src/main/java/com/amazon/carbonado/info/ChainedProperty.java
+++ b/src/main/java/com/amazon/carbonado/info/ChainedProperty.java
@@ -20,7 +20,6 @@ package com.amazon.carbonado.info;
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 
@@ -300,18 +299,42 @@ public class ChainedProperty<S extends Storable> implements Appender {
         }
         if (obj instanceof ChainedProperty) {
             ChainedProperty<?> other = (ChainedProperty<?>) obj;
-            if (getType() == other.getType() && mPrime.equals(other.mPrime)) {
-                if (mChain == null) {
-                    return other.mChain == null;
-                }
-                if (other.mChain != null) {
-                    return Arrays.equals(mChain, other.mChain);
-                }
-            }
+            // Note: Since StorableProperty instances are not canonicalized,
+            // they must be compared with the '==' operator instead of the
+            // equals method. Otherwise, canonical ChainedProperty instances
+            // may refer to StorableProperty instances which are no longer
+            // available through the Introspector.
+            return getType() == other.getType() && mPrime == other.mPrime
+                && identityEquals(mChain, other.mChain);
         }
         return false;
     }
 
+    /**
+     * Compares objects for equality using '==' operator instead of equals method.
+     */
+    private static boolean identityEquals(Object[] a, Object[] a2) {
+        if (a == a2) {
+            return true;
+        }
+        if (a == null || a2 == null) {
+            return false;
+        }
+
+        int length = a.length;
+        if (a2.length != length) {
+            return false;
+        }
+
+        for (int i=0; i<length; i++) {
+            if (a[i] != a2[i]) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
     /**
      * Returns the chained property in a parseable form. The format is
      * "name.subname.subsubname".
-- 
cgit v1.2.3