/common/common-lang/src/main/java/com/twelvemonkeys/util/IgnoreCaseMap.java

https://github.com/conceptboard/TwelveMonkeys · Java · 176 lines · 46 code · 15 blank · 115 comment · 2 complexity · 9d3fcee23100613c1c0bbc03df4c4717 MD5 · raw file

  1. /*
  2. * Copyright (c) 2008, Harald Kuhr
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name "TwelveMonkeys" nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  17. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  18. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  19. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  20. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  21. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  22. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  23. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  24. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  25. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  26. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. */
  28. package com.twelvemonkeys.util;
  29. import java.util.Iterator;
  30. import java.util.Map;
  31. import java.io.Serializable;
  32. /**
  33. * A {@code Map} decorator that makes the mappings in the backing map
  34. * case insensitive
  35. * (this is implemented by converting all keys to uppercase),
  36. * if the keys used are {@code Strings}. If the keys
  37. * used are not {@code String}s, it wil work as a normal
  38. * {@code java.util.Map}.
  39. * <p/>
  40. *
  41. * @see java.util.Map
  42. *
  43. * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
  44. */
  45. public class IgnoreCaseMap<V> extends AbstractDecoratedMap<String, V> implements Serializable, Cloneable {
  46. /**
  47. * Constructs a new empty {@code Map}.
  48. * The backing map will be a {@link java.util.HashMap}
  49. */
  50. public IgnoreCaseMap() {
  51. super();
  52. }
  53. /**
  54. * Constructs a new {@code Map} with the same key-value mappings as the
  55. * given {@code Map}.
  56. * The backing map will be a {@link java.util.HashMap}
  57. * <p/>
  58. * NOTE: As the keys in the given map parameter will be converted to
  59. * uppercase (if they are strings), any duplicate key/value pair where
  60. * {@code key instanceof String && key.equalsIgnoreCase(otherKey)}
  61. * is true, will be lost.
  62. *
  63. * @param pMap the map whose mappings are to be placed in this map.
  64. */
  65. public IgnoreCaseMap(Map<String, ? extends V> pMap) {
  66. super(pMap);
  67. }
  68. /**
  69. * Constructs a new {@code Map} with the same key-value mappings as the
  70. * given {@code Map}.
  71. * <p/>
  72. * NOTE: The backing map is structuraly cahnged, and it should NOT be
  73. * accessed directly, after the wrapped map is created.
  74. * <p/>
  75. * NOTE: As the keys in the given map parameter will be converted to
  76. * uppercase (if they are strings), any duplicate key/value pair where
  77. * {@code key instanceof String && key.equalsIgnoreCase(otherKey)}
  78. * is true, will be lost.
  79. *
  80. * @param pBacking the backing map of this map. Must be either empty, or
  81. * the same map as {@code pContents}.
  82. * @param pContents the map whose mappings are to be placed in this map.
  83. * May be {@code null}
  84. *
  85. * @throws IllegalArgumentException if {@code pBacking} is {@code null}
  86. * @throws IllegalArgumentException if {@code pBacking} differs from
  87. * {@code pContent} and is not empty.
  88. */
  89. public IgnoreCaseMap(Map pBacking, Map<String, ? extends V> pContents) {
  90. super(pBacking, pContents);
  91. }
  92. /**
  93. * Maps the specified key to the specified value in this map.
  94. * Note: If the key used is a string, the key will not be case-sensitive.
  95. *
  96. * @param pKey the map key.
  97. * @param pValue the value.
  98. * @return the previous value of the specified key in this map,
  99. * or null if it did not have one.
  100. */
  101. public V put(String pKey, V pValue) {
  102. String key = (String) toUpper(pKey);
  103. return unwrap(entries.put(key, new BasicEntry<String, V>(key, pValue)));
  104. }
  105. private V unwrap(Entry<String, V> pEntry) {
  106. return pEntry != null ? pEntry.getValue() : null;
  107. }
  108. /**
  109. * Returns the value to which the specified key is mapped in this
  110. * map.
  111. * Note: If the key used is a string, the key will not be case-sensitive.
  112. *
  113. * @param pKey a key in the map
  114. * @return the value to which the key is mapped in this map; null if
  115. * the key is not mapped to any value in this map.
  116. */
  117. public V get(Object pKey) {
  118. return unwrap(entries.get(toUpper(pKey)));
  119. }
  120. /**
  121. * Removes the key (and its corresponding value) from this map. This
  122. * method does nothing if the key is not in the map.
  123. * Note: If the key used is a string, the key will not be case-sensitive.
  124. *
  125. * @param pKey the key that needs to be removed.
  126. * @return the value to which the key had been mapped in this map,
  127. * or null if the key did not have a mapping.
  128. */
  129. public V remove(Object pKey) {
  130. return unwrap(entries.remove(toUpper(pKey)));
  131. }
  132. /**
  133. * Tests if the specified object is a key in this map.
  134. * Note: If the key used is a string, the key will not be case-sensitive.
  135. *
  136. * @param pKey possible key.
  137. * @return true if and only if the specified object is a key in this
  138. * map, as determined by the equals method; false otherwise.
  139. */
  140. public boolean containsKey(Object pKey) {
  141. return entries.containsKey(toUpper(pKey));
  142. }
  143. /**
  144. * Converts the parameter to uppercase, if it's a String.
  145. */
  146. protected static Object toUpper(final Object pObject) {
  147. if (pObject instanceof String) {
  148. return ((String) pObject).toUpperCase();
  149. }
  150. return pObject;
  151. }
  152. protected Iterator<Entry<String, V>> newEntryIterator() {
  153. return (Iterator) entries.entrySet().iterator();
  154. }
  155. protected Iterator<String> newKeyIterator() {
  156. return entries.keySet().iterator();
  157. }
  158. protected Iterator<V> newValueIterator() {
  159. return (Iterator<V>) entries.values().iterator();
  160. }
  161. }