From a278beae5bdaf45bf61fcad08d92d587a60d6adb Mon Sep 17 00:00:00 2001 From: Phil Steitz Date: Mon, 5 Jan 2004 05:26:56 +0000 Subject: [PATCH] Added CaseInsensitiveMap. git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/collections/trunk@131515 13f79535-47bb-0310-9956-ffa450edef68 --- .../collections/map/CaseInsensitiveMap.java | 188 ++++++++++++++++++ .../commons/collections/map/TestAll.java | 5 +- .../map/TestCaseInsensitiveMap.java | 153 ++++++++++++++ 3 files changed, 344 insertions(+), 2 deletions(-) create mode 100644 src/java/org/apache/commons/collections/map/CaseInsensitiveMap.java create mode 100644 src/test/org/apache/commons/collections/map/TestCaseInsensitiveMap.java diff --git a/src/java/org/apache/commons/collections/map/CaseInsensitiveMap.java b/src/java/org/apache/commons/collections/map/CaseInsensitiveMap.java new file mode 100644 index 000000000..eff1e1a23 --- /dev/null +++ b/src/java/org/apache/commons/collections/map/CaseInsensitiveMap.java @@ -0,0 +1,188 @@ +/* + * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/map/CaseInsensitiveMap.java,v 1.1 2004/01/05 05:26:56 psteitz Exp $ + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2004 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowledgement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgement may appear in the software itself, + * if and wherever such third-party acknowledgements normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package org.apache.commons.collections.map; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Map; + +/** + * A case-insensitive Map. + *

+ * As entries are added to the map, keys are converted to all lowercase. A new + * key is compared to existing keys by comparing newKey.toString().toLower() + * to the lowercase values in the current KeySet. + *

+ * Null keys are supported. + *

+ * The keySet() method returns all lowercase keys, or nulls. + *

+ * Example: + *


+ *  Map map = new CaseInsensitiveMap();
+ *  map.put("One", "One");
+ *  map.put("Two", "Two");
+ *  map.put(null, "Three");
+ *  map.put("one", "Four");
+ * 
+ * creates a CaseInsensitiveMap with three entries.
+ * map.get(null) returns "Three" and map.get("ONE") + * returns "Four". The Set returned by keySet() + * equals {"one", "two", null}. + * + * @since Commons Collections 3.0 + * @version $Revision: 1.1 $ $Date: 2004/01/05 05:26:56 $ + * + * @author Commons-Collections team + */ +public class CaseInsensitiveMap extends AbstractHashedMap implements Serializable, Cloneable { + + /** Serialisation version */ + private static final long serialVersionUID = -7074655917369299456L; + + /** + * Constructs a new empty map with default size and load factor. + */ + public CaseInsensitiveMap() { + super(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_THRESHOLD); + } + + /** + * Constructs a new, empty map with the specified initial capacity. + * + * @param initialCapacity the initial capacity + * @throws IllegalArgumentException if the initial capacity is less than one + */ + public CaseInsensitiveMap(int initialCapacity) { + super(initialCapacity); + } + + /** + * Constructs a new, empty map with the specified initial capacity and + * load factor. + * + * @param initialCapacity the initial capacity + * @param loadFactor the load factor + * @throws IllegalArgumentException if the initial capacity is less than one + * @throws IllegalArgumentException if the load factor is less than zero + */ + public CaseInsensitiveMap(int initialCapacity, float loadFactor) { + super(initialCapacity, loadFactor); + } + + /** + * Constructor copying elements from another map. + *

+ * Keys will be converted to lower case strings, which may cause + * some entries to be removed (if string representation of keys differ + * only by character case). + * + * @param map the map to copy + * @throws NullPointerException if the map is null + */ + public CaseInsensitiveMap(Map map) { + super(map); + } + + //----------------------------------------------------------------------- + /** + * Overrides convertKey() from {@link AbstractHashedMap} to convert keys to + * lower case. + *

+ * Returns null if key is null or does not implement toString(). + * + * @param key the key convert + * @return the converted key + */ + protected Object convertKey(Object key) { + if (key != null) { + return key.toString().toLowerCase(); + } else { + return AbstractHashedMap.NULL; + } + } + + //----------------------------------------------------------------------- + /** + * Clones the map without cloning the keys or values. + * + * @return a shallow clone + */ + public Object clone() { + return super.clone(); + } + + /** + * Write the map out using a custom routine. + */ + private void writeObject(ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + doWriteObject(out); + } + + /** + * Read the map in using a custom routine. + */ + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + doReadObject(in); + } + +} diff --git a/src/test/org/apache/commons/collections/map/TestAll.java b/src/test/org/apache/commons/collections/map/TestAll.java index 255472040..1c806bb82 100644 --- a/src/test/org/apache/commons/collections/map/TestAll.java +++ b/src/test/org/apache/commons/collections/map/TestAll.java @@ -1,5 +1,5 @@ /* - * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/test/org/apache/commons/collections/map/TestAll.java,v 1.11 2003/12/14 21:42:55 psteitz Exp $ + * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/test/org/apache/commons/collections/map/TestAll.java,v 1.12 2004/01/05 05:26:56 psteitz Exp $ * ==================================================================== * * The Apache Software License, Version 1.1 @@ -65,7 +65,7 @@ import junit.framework.TestSuite; * Entry point for tests. * * @since Commons Collections 3.0 - * @version $Revision: 1.11 $ $Date: 2003/12/14 21:42:55 $ + * @version $Revision: 1.12 $ $Date: 2004/01/05 05:26:56 $ * * @author Stephen Colebourne */ @@ -83,6 +83,7 @@ public class TestAll extends TestCase { public static Test suite() { TestSuite suite = new TestSuite(); + suite.addTest(TestCaseInsensitiveMap.suite()); suite.addTest(TestCompositeMap.suite()); suite.addTest(TestFlat3Map.suite()); suite.addTest(TestHashedMap.suite()); diff --git a/src/test/org/apache/commons/collections/map/TestCaseInsensitiveMap.java b/src/test/org/apache/commons/collections/map/TestCaseInsensitiveMap.java new file mode 100644 index 000000000..372fe058b --- /dev/null +++ b/src/test/org/apache/commons/collections/map/TestCaseInsensitiveMap.java @@ -0,0 +1,153 @@ +/* + * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/test/org/apache/commons/collections/map/TestCaseInsensitiveMap.java,v 1.1 2004/01/05 05:26:56 psteitz Exp $ + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2004 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowledgement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgement may appear in the software itself, + * if and wherever such third-party acknowledgements normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package org.apache.commons.collections.map; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import junit.framework.Test; +import junit.textui.TestRunner; + +import org.apache.commons.collections.BulkTest; + +/** + * Tests for the {@link CaseInsensitiveMap} implementation. + * + * @version $Revision: 1.1 $ $Date: 2004/01/05 05:26:56 $ + * + * @author Commons-Collections team + */ +public class TestCaseInsensitiveMap extends AbstractTestIterableMap { + + public TestCaseInsensitiveMap(String testName) { + super(testName); + } + + public static void main(String[] args) { + TestRunner.run(suite()); + } + + public static Test suite() { + return BulkTest.makeSuite(TestCaseInsensitiveMap.class); + } + + public Map makeEmptyMap() { + return new CaseInsensitiveMap(); + } + + public String getCompatibilityVersion() { + return "3"; + } + + //------------------------------------------------------------------------- + + public void testCaseInsensitive() { + Map map = new CaseInsensitiveMap(); + map.put("One", "One"); + map.put("Two", "Two"); + assertEquals("One", (String) map.get("one")); + assertEquals("One", (String) map.get("oNe")); + map.put("two", "Three"); + assertEquals("Three", (String) map.get("Two")); + } + + public void testNullHandling() { + Map map = new CaseInsensitiveMap(); + map.put("One", "One"); + map.put("Two", "Two"); + map.put(null, "Three"); + assertEquals("Three", (String) map.get(null)); + map.put(null, "Four"); + assertEquals("Four", (String) map.get(null)); + Set keys = map.keySet(); + assertTrue(keys.contains("one")); + assertTrue(keys.contains("two")); + assertTrue(keys.contains(null)); + assertTrue(keys.size() == 3); + } + + public void testPutAll() { + Map map = new HashMap(); + map.put("One", "One"); + map.put("Two", "Two"); + map.put("one", "Three"); + map.put(null, "Four"); + map.put(new Integer(20), "Five"); + Map caseInsensitiveMap = new CaseInsensitiveMap(map); + assertTrue(caseInsensitiveMap.size() == 4); // ones collapsed + Set keys = caseInsensitiveMap.keySet(); + assertTrue(keys.contains("one")); + assertTrue(keys.contains("two")); + assertTrue(keys.contains(null)); + assertTrue(keys.contains(Integer.toString(20))); + assertTrue(keys.size() == 4); + assertTrue(!caseInsensitiveMap.containsValue("One") + || !caseInsensitiveMap.containsValue("Three")); // ones collaped + assertEquals(caseInsensitiveMap.get(null), "Four"); + } + + /* + public void testCreate() throws Exception { + resetEmpty(); + writeExternalFormToDisk((java.io.Serializable) map, "/home/phil/jakarta-commons/collections/data/test/CaseInsensitiveMap.emptyCollection.version3.obj"); + resetFull(); + writeExternalFormToDisk((java.io.Serializable) map, "/home/phil/jakarta-commons/collections/data/test/CaseInsensitiveMap.fullCollection.version3.obj"); + } + */ +}