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.Map;
  22. import org.apache.commons.collections.Factory;
  23. import org.apache.commons.collections.Transformer;
  24. import org.apache.commons.collections.functors.FactoryTransformer;
  25. /**
  26. * Decorates another <code>Map</code> to create objects in the map on demand.
  27. * <p>
  28. * When the {@link #get(Object)} method is called with a key that does not
  29. * exist in the map, the factory is used to create the object. The created
  30. * object will be added to the map using the requested key.
  31. * <p>
  32. * For instance:
  33. * <pre>
  34. * Factory factory = new Factory() {
  35. * public Object create() {
  36. * return new Date();
  37. * }
  38. * }
  39. * Map lazy = Lazy.map(new HashMap(), factory);
  40. * Object obj = lazy.get("NOW");
  41. * </pre>
  42. *
  43. * After the above code is executed, <code>obj</code> will contain
  44. * a new <code>Date</code> instance. Furthermore, that <code>Date</code>
  45. * instance is mapped to the "NOW" key in the map.
  46. * <p>
  47. * This class is Serializable from Commons Collections 3.1.
  48. *
  49. * @since Commons Collections 3.0
  50. * @version $Revision: 1.7 $ $Date: 2004/05/07 23:30:33 $
  51. *
  52. * @author Stephen Colebourne
  53. * @author Paul Jack
  54. */
  55. public class LazyMap
  56. extends AbstractMapDecorator
  57. implements Map, Serializable {
  58. /** Serialization version */
  59. private static final long serialVersionUID = 7990956402564206740L;
  60. /** The factory to use to construct elements */
  61. protected final Transformer factory;
  62. /**
  63. * Factory method to create a lazily instantiated map.
  64. *
  65. * @param map the map to decorate, must not be null
  66. * @param factory the factory to use, must not be null
  67. * @throws IllegalArgumentException if map or factory is null
  68. */
  69. public static Map decorate(Map map, Factory factory) {
  70. return new LazyMap(map, factory);
  71. }
  72. /**
  73. * Factory method to create a lazily instantiated map.
  74. *
  75. * @param map the map to decorate, must not be null
  76. * @param factory the factory to use, must not be null
  77. * @throws IllegalArgumentException if map or factory is null
  78. */
  79. public static Map decorate(Map map, Transformer factory) {
  80. return new LazyMap(map, factory);
  81. }
  82. //-----------------------------------------------------------------------
  83. /**
  84. * Constructor that wraps (not copies).
  85. *
  86. * @param map the map to decorate, must not be null
  87. * @param factory the factory to use, must not be null
  88. * @throws IllegalArgumentException if map or factory is null
  89. */
  90. protected LazyMap(Map map, Factory factory) {
  91. super(map);
  92. if (factory == null) {
  93. throw new IllegalArgumentException("Factory must not be null");
  94. }
  95. this.factory = FactoryTransformer.getInstance(factory);
  96. }
  97. /**
  98. * Constructor that wraps (not copies).
  99. *
  100. * @param map the map to decorate, must not be null
  101. * @param factory the factory to use, must not be null
  102. * @throws IllegalArgumentException if map or factory is null
  103. */
  104. protected LazyMap(Map map, Transformer factory) {
  105. super(map);
  106. if (factory == null) {
  107. throw new IllegalArgumentException("Factory must not be null");
  108. }
  109. this.factory = factory;
  110. }
  111. //-----------------------------------------------------------------------
  112. /**
  113. * Write the map out using a custom routine.
  114. *
  115. * @param out the output stream
  116. * @throws IOException
  117. * @since Commons Collections 3.1
  118. */
  119. private void writeObject(ObjectOutputStream out) throws IOException {
  120. out.defaultWriteObject();
  121. out.writeObject(map);
  122. }
  123. /**
  124. * Read the map in using a custom routine.
  125. *
  126. * @param in the input stream
  127. * @throws IOException
  128. * @throws ClassNotFoundException
  129. * @since Commons Collections 3.1
  130. */
  131. private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
  132. in.defaultReadObject();
  133. map = (Map) in.readObject();
  134. }
  135. //-----------------------------------------------------------------------
  136. public Object get(Object key) {
  137. // create value for key if key is not currently in the map
  138. if (map.containsKey(key) == false) {
  139. Object value = factory.transform(key);
  140. map.put(key, value);
  141. return value;
  142. }
  143. return map.get(key);
  144. }
  145. // no need to wrap keySet, entrySet or values as they are views of
  146. // existing map entries - you can't do a map-style get on them.
  147. }