1. /*
  2. * Copyright 2003-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.apache.commons.collections.map;
  17. import java.io.IOException;
  18. import java.io.ObjectInputStream;
  19. import java.io.ObjectOutputStream;
  20. import java.io.Serializable;
  21. import java.util.Iterator;
  22. import java.util.Map;
  23. import org.apache.commons.collections.Transformer;
  24. /**
  25. * Decorates another <code>Map</code> to transform objects that are added.
  26. * <p>
  27. * The Map put methods and Map.Entry setValue method are affected by this class.
  28. * Thus objects must be removed or searched for using their transformed form.
  29. * For example, if the transformation converts Strings to Integers, you must
  30. * use the Integer form to remove objects.
  31. * <p>
  32. * This class is Serializable from Commons Collections 3.1.
  33. *
  34. * @since Commons Collections 3.0
  35. * @version $Revision: 1.11 $ $Date: 2004/06/07 22:14:42 $
  36. *
  37. * @author Stephen Colebourne
  38. */
  39. public class TransformedMap
  40. extends AbstractInputCheckedMapDecorator
  41. implements Serializable {
  42. /** Serialization version */
  43. private static final long serialVersionUID = 7023152376788900464L;
  44. /** The transformer to use for the key */
  45. protected final Transformer keyTransformer;
  46. /** The transformer to use for the value */
  47. protected final Transformer valueTransformer;
  48. /**
  49. * Factory method to create a transforming map.
  50. * <p>
  51. * If there are any elements already in the map being decorated, they
  52. * are NOT transformed.
  53. *
  54. * @param map the map to decorate, must not be null
  55. * @param keyTransformer the transformer to use for key conversion, null means no conversion
  56. * @param valueTransformer the transformer to use for value conversion, null means no conversion
  57. * @throws IllegalArgumentException if map is null
  58. */
  59. public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
  60. return new TransformedMap(map, keyTransformer, valueTransformer);
  61. }
  62. //-----------------------------------------------------------------------
  63. /**
  64. * Constructor that wraps (not copies).
  65. * <p>
  66. * If there are any elements already in the collection being decorated, they
  67. * are NOT transformed.
  68. *
  69. * @param map the map to decorate, must not be null
  70. * @param keyTransformer the transformer to use for key conversion, null means no conversion
  71. * @param valueTransformer the transformer to use for value conversion, null means no conversion
  72. * @throws IllegalArgumentException if map is null
  73. */
  74. protected TransformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {
  75. super(map);
  76. this.keyTransformer = keyTransformer;
  77. this.valueTransformer = valueTransformer;
  78. }
  79. //-----------------------------------------------------------------------
  80. /**
  81. * Write the map out using a custom routine.
  82. *
  83. * @param out the output stream
  84. * @throws IOException
  85. * @since Commons Collections 3.1
  86. */
  87. private void writeObject(ObjectOutputStream out) throws IOException {
  88. out.defaultWriteObject();
  89. out.writeObject(map);
  90. }
  91. /**
  92. * Read the map in using a custom routine.
  93. *
  94. * @param in the input stream
  95. * @throws IOException
  96. * @throws ClassNotFoundException
  97. * @since Commons Collections 3.1
  98. */
  99. private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
  100. in.defaultReadObject();
  101. map = (Map) in.readObject();
  102. }
  103. //-----------------------------------------------------------------------
  104. /**
  105. * Transforms a key.
  106. * <p>
  107. * The transformer itself may throw an exception if necessary.
  108. *
  109. * @param object the object to transform
  110. * @throws the transformed object
  111. */
  112. protected Object transformKey(Object object) {
  113. if (keyTransformer == null) {
  114. return object;
  115. }
  116. return keyTransformer.transform(object);
  117. }
  118. /**
  119. * Transforms a value.
  120. * <p>
  121. * The transformer itself may throw an exception if necessary.
  122. *
  123. * @param object the object to transform
  124. * @throws the transformed object
  125. */
  126. protected Object transformValue(Object object) {
  127. if (valueTransformer == null) {
  128. return object;
  129. }
  130. return valueTransformer.transform(object);
  131. }
  132. /**
  133. * Transforms a map.
  134. * <p>
  135. * The transformer itself may throw an exception if necessary.
  136. *
  137. * @param map the map to transform
  138. * @throws the transformed object
  139. */
  140. protected Map transformMap(Map map) {
  141. Map result = new LinkedMap(map.size());
  142. for (Iterator it = map.entrySet().iterator(); it.hasNext(); ) {
  143. Map.Entry entry = (Map.Entry) it.next();
  144. result.put(transformKey(entry.getKey()), transformValue(entry.getValue()));
  145. }
  146. return result;
  147. }
  148. /**
  149. * Override to transform the value when using <code>setValue</code>.
  150. *
  151. * @param value the value to transform
  152. * @return the transformed value
  153. * @since Commons Collections 3.1
  154. */
  155. protected Object checkSetValue(Object value) {
  156. return valueTransformer.transform(value);
  157. }
  158. /**
  159. * Override to only return true when there is a value transformer.
  160. *
  161. * @return true if a value transformer is in use
  162. * @since Commons Collections 3.1
  163. */
  164. protected boolean isSetValueChecking() {
  165. return (valueTransformer != null);
  166. }
  167. //-----------------------------------------------------------------------
  168. public Object put(Object key, Object value) {
  169. key = transformKey(key);
  170. value = transformValue(value);
  171. return getMap().put(key, value);
  172. }
  173. public void putAll(Map mapToCopy) {
  174. mapToCopy = transformMap(mapToCopy);
  175. getMap().putAll(mapToCopy);
  176. }
  177. }