1 /*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
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 * A copy of the License is located at
7 *
8 * http://aws.amazon.com/apache2.0
9 *
10 * or in the "license" file accompanying this file. This file is distributed
11 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 * express or implied. See the License for the specific language governing
13 * permissions and limitations under the License.
14 */
15
16 package software.amazon.awssdk.utils;
17
18 import java.util.Collection;
19 import java.util.Collections;
20 import java.util.HashMap;
21 import java.util.Map;
22 import java.util.Set;
23 import software.amazon.awssdk.annotations.SdkProtectedApi;
24
25 /**
26 * An immutable map that could be built by convenient constructors.
27 * <p>
28 * Example of using map Builder:
29 *
30 * <pre>
31 * {
32 * @code
33 * Map<String, AttibuteValue> item = new ImmutableMap.Builder<String, AttibuteValue>()
34 * .put("one", new AttibuteValue("1"))
35 * .put("two", new AttibuteValue("2"))
36 * .put("three", new AttibuteValue("3")).build();
37 * }
38 * </pre>
39 *
40 * For <i>small</i> immutable maps (up to five entries), the
41 * {@code ImmutableMapParamter.of()} methods are preferred:
42 *
43 * <pre>
44 * {@code
45 * Map<String, AttibuteValue> item =
46 * ImmutableMap
47 * .of("one", new AttributeValue("1"),
48 * "two", new AttributeValue("2"),
49 * "three", new AttributeValue("3"),
50 * }
51 * </pre>
52 *
53 * @param <K>
54 * Class of the key for the map.
55 * @param <V>
56 * Class of the value for the map.
57 */
58 @SdkProtectedApi
59 public final class ImmutableMap<K, V> implements Map<K, V> {
60
61 private static final String UNMODIFIABLE_MESSAGE = "This is an immutable map.";
62 private static final String DUPLICATED_KEY_MESSAGE = "Duplicate keys are provided.";
63
64 private final Map<K, V> map;
65
66 private ImmutableMap(Map<K, V> map) {
67 this.map = map;
68 }
69
70 /**
71 * Returns a new MapParameterBuilder instance.
72 */
73 public static <K, V> Builder<K, V> builder() {
74 return new Builder<>();
75 }
76
77 /**
78 * Returns an ImmutableMap instance containing a single entry.
79 *
80 * @param k0
81 * Key of the single entry.
82 * @param v0
83 * Value of the single entry.
84 */
85 public static <K, V> ImmutableMap<K, V> of(K k0, V v0) {
86 Map<K, V> map = Collections.singletonMap(k0, v0);
87 return new ImmutableMap<>(map);
88 }
89
90 /**
91 * Returns an ImmutableMap instance containing two entries.
92 *
93 * @param k0
94 * Key of the first entry.
95 * @param v0
96 * Value of the first entry.
97 * @param k1
98 * Key of the second entry.
99 * @param v1
100 * Value of the second entry.
101 */
102 public static <K, V> ImmutableMap<K, V> of(K k0, V v0, K k1, V v1) {
103 Map<K, V> map = new HashMap<>();
104 putAndWarnDuplicateKeys(map, k0, v0);
105 putAndWarnDuplicateKeys(map, k1, v1);
106 return new ImmutableMap<>(map);
107 }
108
109 /**
110 * Returns an ImmutableMap instance containing three entries.
111 *
112 * @param k0
113 * Key of the first entry.
114 * @param v0
115 * Value of the first entry.
116 * @param k1
117 * Key of the second entry.
118 * @param v1
119 * Value of the second entry.
120 * @param k2
121 * Key of the third entry.
122 * @param v2
123 * Value of the third entry.
124 */
125 public static <K, V> ImmutableMap<K, V> of(K k0, V v0, K k1, V v1,
126 K k2, V v2) {
127 Map<K, V> map = new HashMap<>();
128 putAndWarnDuplicateKeys(map, k0, v0);
129 putAndWarnDuplicateKeys(map, k1, v1);
130 putAndWarnDuplicateKeys(map, k2, v2);
131 return new ImmutableMap<>(map);
132 }
133
134 /**
135 * Returns an ImmutableMap instance containing four entries.
136 *
137 * @param k0
138 * Key of the first entry.
139 * @param v0
140 * Value of the first entry.
141 * @param k1
142 * Key of the second entry.
143 * @param v1
144 * Value of the second entry.
145 * @param k2
146 * Key of the third entry.
147 * @param v2
148 * Value of the third entry.
149 * @param k3
150 * Key of the fourth entry.
151 * @param v3
152 * Value of the fourth entry.
153 */
154 public static <K, V> ImmutableMap<K, V> of(K k0, V v0, K k1, V v1,
155 K k2, V v2, K k3, V v3) {
156 Map<K, V> map = new HashMap<>();
157 putAndWarnDuplicateKeys(map, k0, v0);
158 putAndWarnDuplicateKeys(map, k1, v1);
159 putAndWarnDuplicateKeys(map, k2, v2);
160 putAndWarnDuplicateKeys(map, k3, v3);
161 return new ImmutableMap<>(map);
162 }
163
164 /**
165 * Returns an ImmutableMap instance containing five entries.
166 *
167 * @param k0
168 * Key of the first entry.
169 * @param v0
170 * Value of the first entry.
171 * @param k1
172 * Key of the second entry.
173 * @param v1
174 * Value of the second entry.
175 * @param k2
176 * Key of the third entry.
177 * @param v2
178 * Value of the third entry.
179 * @param k3
180 * Key of the fourth entry.
181 * @param v3
182 * Value of the fourth entry.
183 * @param k4
184 * Key of the fifth entry.
185 * @param v4
186 * Value of the fifth entry.
187 */
188 public static <K, V> ImmutableMap<K, V> of(K k0, V v0, K k1, V v1,
189 K k2, V v2, K k3, V v3, K k4, V v4) {
190 Map<K, V> map = new HashMap<>();
191 putAndWarnDuplicateKeys(map, k0, v0);
192 putAndWarnDuplicateKeys(map, k1, v1);
193 putAndWarnDuplicateKeys(map, k2, v2);
194 putAndWarnDuplicateKeys(map, k3, v3);
195 putAndWarnDuplicateKeys(map, k4, v4);
196 return new ImmutableMap<>(map);
197 }
198
199 private static <K, V> void putAndWarnDuplicateKeys(Map<K, V> map, K key,
200 V value) {
201 if (map.containsKey(key)) {
202 throw new IllegalArgumentException(DUPLICATED_KEY_MESSAGE);
203 }
204 map.put(key, value);
205 }
206
207 /** Inherited methods **/
208
209 public boolean containsKey(Object key) {
210 return map.containsKey(key);
211 }
212
213 public boolean containsValue(Object value) {
214 return map.containsValue(value);
215 }
216
217 public Set<Entry<K, V>> entrySet() {
218 return map.entrySet();
219 }
220
221 public V get(Object key) {
222 return map.get(key);
223 }
224
225 public boolean isEmpty() {
226 return map.isEmpty();
227 }
228
229 public Set<K> keySet() {
230 return map.keySet();
231 }
232
233 public int size() {
234 return map.size();
235 }
236
237 public Collection<V> values() {
238 return map.values();
239 }
240
241 /** Unsupported methods **/
242
243 public void clear() {
244 throw new UnsupportedOperationException(UNMODIFIABLE_MESSAGE);
245 }
246
247 public V put(K key, V value) {
248 throw new UnsupportedOperationException(UNMODIFIABLE_MESSAGE);
249 }
250
251 public void putAll(Map<? extends K, ? extends V> map) {
252 throw new UnsupportedOperationException(UNMODIFIABLE_MESSAGE);
253 }
254
255 public V remove(Object key) {
256 throw new UnsupportedOperationException(UNMODIFIABLE_MESSAGE);
257 }
258
259 @Override
260 public boolean equals(Object o) {
261 return map.equals(o);
262 }
263
264 @Override
265 public int hashCode() {
266 return map.hashCode();
267 }
268
269 @Override
270 public String toString() {
271 return map.toString();
272 }
273
274 /**
275 * A convenient builder for creating ImmutableMap instances.
276 */
277 public static class Builder<K, V> {
278
279 private final Map<K, V> entries;
280
281 public Builder() {
282 this.entries = new HashMap<>();
283 }
284
285 /**
286 * Add a key-value pair into the built map. The method will throw
287 * IllegalArgumentException immediately when duplicate keys are
288 * provided.
289 *
290 * @return Returns a reference to this object so that method calls can
291 * be chained together.
292 */
293 public Builder<K, V> put(K key, V value) {
294 putAndWarnDuplicateKeys(entries, key, value);
295 return this;
296 }
297
298 /**
299 * Generates and returns a new ImmutableMap instance which
300 * contains all the entries added into the Builder by {@code put()}
301 * method.
302 */
303 public ImmutableMap<K, V> build() {
304 HashMap<K, V> builtMap = new HashMap<>(entries);
305 return new ImmutableMap<>(builtMap);
306 }
307 }
308 }
309