Index: BasicRowProcessor.java =================================================================== --- BasicRowProcessor.java (revision 536476) +++ BasicRowProcessor.java (working copy) @@ -144,10 +144,36 @@ * A Map that converts all keys to lowercase Strings for case insensitive * lookups. This is needed for the toMap() implementation because * databases don't consistenly handle the casing of column names. + * + *

The keys are stored as they are given [BUG #DBUTILS-34], so we maintain + * an internal mapping from lowercase keys to the real keys in order to + * achieve the case insensitive lookup. + * + *

Note: This implementation does not allow null + * for key, whereas {@link HashMap} does, because of the code: + *

+     * key.toString().toLowerCase()
+     * 
*/ private static class CaseInsensitiveHashMap extends HashMap { /** + * The internal mapping from lowercase keys to the real keys. + * + *

+ * Any query operation using the key + * ({@link #get(Object)}, {@link #containsKey(Object)}) + * is done in three steps: + *

+ *

+ */ + private Map lowerCaseMap = new HashMap(); + + /** * Required for serialization support. * * @see java.io.Serializable @@ -158,21 +184,37 @@ * @see java.util.Map#containsKey(java.lang.Object) */ public boolean containsKey(Object key) { - return super.containsKey(key.toString().toLowerCase()); + Object realKey = lowerCaseMap.get(key.toString().toLowerCase()); + return super.containsKey(realKey); + // Possible optimisation here: + // Since the lowerCaseMap contains a mapping for all the keys, + // we could just do this: + // return lowerCaseMap.containsKey(key.toString().toLowerCase()); } /** * @see java.util.Map#get(java.lang.Object) */ public Object get(Object key) { - return super.get(key.toString().toLowerCase()); + Object realKey = lowerCaseMap.get(key.toString().toLowerCase()); + return super.get(realKey); } /** * @see java.util.Map#put(java.lang.Object, java.lang.Object) */ public Object put(Object key, Object value) { - return super.put(key.toString().toLowerCase(), value); + /* + * In order to keep the map and lowerCaseMap synchronized, + * we have to remove the old mapping before putting the + * new one. Indeed, oldKey and key are not necessaliry equals. + * (That's why we call super.remove(oldKey) and not just + * super.put(key, value)) + */ + Object oldKey = lowerCaseMap.put(key.toString().toLowerCase(), key); + Object oldValue = super.remove(oldKey); + super.put(key, value); + return oldValue; } /** @@ -191,7 +233,8 @@ * @see java.util.Map#remove(java.lang.Object) */ public Object remove(Object key) { - return super.remove(key.toString().toLowerCase()); + Object realKey = lowerCaseMap.remove(key.toString().toLowerCase()); + return super.remove(realKey); } }