KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > collections > map > DefaultedMap


1 /*
2  * Copyright 2005 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
18 import java.io.IOException JavaDoc;
19 import java.io.ObjectInputStream JavaDoc;
20 import java.io.ObjectOutputStream JavaDoc;
21 import java.io.Serializable JavaDoc;
22 import java.util.HashMap JavaDoc;
23 import java.util.Map JavaDoc;
24
25 import org.apache.commons.collections.Factory;
26 import org.apache.commons.collections.Transformer;
27 import org.apache.commons.collections.functors.ConstantTransformer;
28 import org.apache.commons.collections.functors.FactoryTransformer;
29
30 /**
31  * Decorates another <code>Map</code> returning a default value if the map
32  * does not contain the requested key.
33  * <p>
34  * When the {@link #get(Object)} method is called with a key that does not
35  * exist in the map, this map will return the default value specified in
36  * the constructor/factory. Only the get method is altered, so the
37  * {@link Map#containsKey(Object)} can be used to determine if a key really
38  * is in the map or not.
39  * <p>
40  * The defaulted value is not added to the map.
41  * Compare this behaviour with {@link LazyMap}, which does add the value
42  * to the map (via a Transformer).
43  * <p>
44  * For instance:
45  * <pre>
46  * Map map = new DefaultedMap("NULL");
47  * Object obj = map.get("Surname");
48  * // obj == "NULL"
49  * </pre>
50  * After the above code is executed the map is still empty.
51  * <p>
52  * <strong>Note that DefaultedMap is not synchronized and is not thread-safe.</strong>
53  * If you wish to use this map from multiple threads concurrently, you must use
54  * appropriate synchronization. The simplest approach is to wrap this map
55  * using {@link java.util.Collections#synchronizedMap(Map)}. This class may throw
56  * exceptions when accessed by concurrent threads without synchronization.
57  *
58  * @since Commons Collections 3.2
59  * @version $Revision: 1.7 $ $Date: 2005-11-21 22:52:57 +0000 (Mon, 21 Nov 2005) $
60  *
61  * @author Stephen Colebourne
62  * @author Rafael U.C. Afonso
63  * @see LazyMap
64  */

65 public class DefaultedMap
66         extends AbstractMapDecorator
67         implements Map JavaDoc, Serializable JavaDoc {
68
69     /** Serialization version */
70     private static final long serialVersionUID = 19698628745827L;
71
72     /** The transformer to use if the map does not contain a key */
73     protected final Object JavaDoc value;
74
75     //-----------------------------------------------------------------------
76
/**
77      * Factory method to create a defaulting map.
78      * <p>
79      * The value specified is returned when a missing key is found.
80      *
81      * @param map the map to decorate, must not be null
82      * @param defaultValue the default value to return when the key is not found
83      * @throws IllegalArgumentException if map is null
84      */

85     public static Map JavaDoc decorate(Map JavaDoc map, Object JavaDoc defaultValue) {
86         if (defaultValue instanceof Transformer) {
87             defaultValue = ConstantTransformer.getInstance(defaultValue);
88         }
89         return new DefaultedMap(map, defaultValue);
90     }
91
92     /**
93      * Factory method to create a defaulting map.
94      * <p>
95      * The factory specified is called when a missing key is found.
96      * The result will be returned as the result of the map get(key) method.
97      *
98      * @param map the map to decorate, must not be null
99      * @param factory the factory to use, must not be null
100      * @throws IllegalArgumentException if map or factory is null
101      */

102     public static Map JavaDoc decorate(Map JavaDoc map, Factory factory) {
103         if (factory == null) {
104             throw new IllegalArgumentException JavaDoc("Factory must not be null");
105         }
106         return new DefaultedMap(map, FactoryTransformer.getInstance(factory));
107     }
108
109     /**
110      * Factory method to create a defaulting map.
111      * <p>
112      * The transformer specified is called when a missing key is found.
113      * The key is passed to the transformer as the input, and the result
114      * will be returned as the result of the map get(key) method.
115      *
116      * @param map the map to decorate, must not be null
117      * @param factory the factory to use, must not be null
118      * @throws IllegalArgumentException if map or factory is null
119      */

120     public static Map JavaDoc decorate(Map JavaDoc map, Transformer factory) {
121         if (factory == null) {
122            throw new IllegalArgumentException JavaDoc("Transformer must not be null");
123        }
124        return new DefaultedMap(map, factory);
125     }
126
127     //-----------------------------------------------------------------------
128
/**
129      * Constructs a new empty <code>DefaultedMap</code> that decorates
130      * a <code>HashMap</code>.
131      * <p>
132      * The object passed in will be returned by the map whenever an
133      * unknown key is requested.
134      *
135      * @param defaultValue the default value to return when the key is not found
136      */

137     public DefaultedMap(Object JavaDoc defaultValue) {
138         super(new HashMap JavaDoc());
139         if (defaultValue instanceof Transformer) {
140             defaultValue = ConstantTransformer.getInstance(defaultValue);
141         }
142         this.value = defaultValue;
143     }
144
145     /**
146      * Constructor that wraps (not copies).
147      *
148      * @param map the map to decorate, must not be null
149      * @param value the value to use
150      * @throws IllegalArgumentException if map or transformer is null
151      */

152     protected DefaultedMap(Map JavaDoc map, Object JavaDoc value) {
153         super(map);
154         this.value = value;
155     }
156
157     //-----------------------------------------------------------------------
158
/**
159      * Write the map out using a custom routine.
160      *
161      * @param out the output stream
162      * @throws IOException
163      */

164     private void writeObject(ObjectOutputStream JavaDoc out) throws IOException JavaDoc {
165         out.defaultWriteObject();
166         out.writeObject(map);
167     }
168
169     /**
170      * Read the map in using a custom routine.
171      *
172      * @param in the input stream
173      * @throws IOException
174      * @throws ClassNotFoundException
175      */

176     private void readObject(ObjectInputStream JavaDoc in) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
177         in.defaultReadObject();
178         map = (Map JavaDoc) in.readObject();
179     }
180
181     //-----------------------------------------------------------------------
182
public Object JavaDoc get(Object JavaDoc key) {
183         // create value for key if key is not currently in the map
184
if (map.containsKey(key) == false) {
185             if (value instanceof Transformer) {
186                 return ((Transformer) value).transform(key);
187             }
188             return value;
189         }
190         return map.get(key);
191     }
192
193     // no need to wrap keySet, entrySet or values as they are views of
194
// existing map entries - you can't do a map-style get on them.
195
}
196
Popular Tags