Author: dfabulich Date: Wed Feb 11 08:08:01 2009 New Revision: 743269 URL: http://svn.apache.org/viewvc?rev=743269&view=rev Log: [DBUTILS-34] BasicRowProcessor loses any information on database field case Submitted by: Julien Aymé
Modified: commons/sandbox/dbutils/bugfixing/src/java/org/apache/commons/dbutils/BasicRowProcessor.java Modified: commons/sandbox/dbutils/bugfixing/src/java/org/apache/commons/dbutils/BasicRowProcessor.java URL: http://svn.apache.org/viewvc/commons/sandbox/dbutils/bugfixing/src/java/org/apache/commons/dbutils/BasicRowProcessor.java?rev=743269&r1=743268&r2=743269&view=diff ============================================================================== --- commons/sandbox/dbutils/bugfixing/src/java/org/apache/commons/dbutils/BasicRowProcessor.java (original) +++ commons/sandbox/dbutils/bugfixing/src/java/org/apache/commons/dbutils/BasicRowProcessor.java Wed Feb 11 08:08:01 2009 @@ -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. + * + * <p>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. + * + * <p>Note: This implementation does not allow <tt>null</tt> + * for key, whereas {...@link HashMap} does, because of the code: + * <pre> + * key.toString().toLowerCase() + * </pre> */ private static class CaseInsensitiveHashMap extends HashMap { /** + * The internal mapping from lowercase keys to the real keys. + * + * <p> + * Any query operation using the key + * ({...@link #get(Object)}, {...@link #containsKey(Object)}) + * is done in three steps: + * <ul> + * <li>convert the parameter key to lower case</li> + * <li>get the actual key that corresponds to the lower case key</li> + * <li>query the map with the actual key</li> + * </ul> + * </p> + */ + 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); } }