001 /*
002 * Copyright 2008-2017 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package griffon.util;
017
018 import javax.annotation.Nonnull;
019 import java.util.ArrayList;
020 import java.util.Arrays;
021 import java.util.Collection;
022 import java.util.Collections;
023 import java.util.Enumeration;
024 import java.util.HashMap;
025 import java.util.HashSet;
026 import java.util.Iterator;
027 import java.util.LinkedHashMap;
028 import java.util.LinkedHashSet;
029 import java.util.List;
030 import java.util.ListIterator;
031 import java.util.Map;
032 import java.util.Properties;
033 import java.util.Set;
034
035 import static java.util.Objects.requireNonNull;
036
037 /**
038 * <p>Utility class that simplifies creating collections in Java.</p>
039 * <p><strong>Creating Maps</strong><br/>
040 * <pre>
041 * Map<String, Object> m = map()
042 * .e("foo", foo)
043 * .e("bar", bar);
044 * </pre></p>
045 *
046 * <p><strong>Creating Lists</strong><br/>
047 * <pre>
048 * List<String> l = list()
049 * .e("foo")
050 * .e("bar");
051 * </pre></p>
052 *
053 * <p><strong>Creating Maps</strong><br/>
054 * <pre>
055 * Set<String> s = set()
056 * .e("foo")
057 * .e("bar");
058 * </pre></p>
059 *
060 * @author Andres Almiray
061 * @since 2.0.0
062 */
063 public final class CollectionUtils {
064 private static final String ERROR_MAP_NULL = "Argument 'map' must not be null";
065
066 public static <T> List<T> reverse(List<T> input) {
067 List<T> output = new ArrayList<>(input);
068 Collections.reverse(output);
069 return output;
070 }
071
072 public static <T> List<T> reverse(Collection<T> input) {
073 List<T> output = new ArrayList<>(input);
074 Collections.reverse(output);
075 return output;
076 }
077
078 @SuppressWarnings({"rawtypes", "unchecked"})
079 public static <K, V> Map newMap(Object... keysAndValues) {
080 if (keysAndValues == null) {
081 return Collections.emptyMap();
082 }
083 if (keysAndValues.length % 2 == 1) {
084 throw new IllegalArgumentException("Must have an even number of keys and values");
085 }
086
087 Map<K, V> map = new HashMap<>();
088 for (int i = 0; i < keysAndValues.length; i += 2) {
089 map.put((K) keysAndValues[i], (V) keysAndValues[i + 1]);
090 }
091 return map;
092 }
093
094 @SafeVarargs
095 public static <T> Set<T> newSet(T... values) {
096 if (values == null) {
097 return Collections.emptySet();
098 }
099
100 return new HashSet<>(Arrays.asList(values));
101 }
102
103 @SafeVarargs
104 public static <T> List<T> newList(T... values) {
105 if (values == null) {
106 return Collections.emptyList();
107 }
108
109 return new ArrayList<>(Arrays.asList(values));
110 }
111
112 public static <K, V> MapBuilder<K, V> map() {
113 return map(new LinkedHashMap<K, V>());
114 }
115
116 public static <K, V> MapBuilder<K, V> map(Map<K, V> delegate) {
117 return new MapBuilder<>(delegate);
118 }
119
120 public static <E> ListBuilder<E> list() {
121 return list(new ArrayList<E>());
122 }
123
124 public static <E> ListBuilder<E> list(List<E> delegate) {
125 return new ListBuilder<>(delegate);
126 }
127
128 public static <E> SetBuilder<E> set() {
129 return set(new HashSet<E>());
130 }
131
132 public static <E> SetBuilder<E> set(Set<E> delegate) {
133 return new SetBuilder<>(delegate);
134 }
135
136 /**
137 * Returns an adapted Map as a Properties instance.
138 * <p>
139 * The Map is used live, which means changes made to it will affect the
140 * Properties instance directly.
141 *
142 * @param map the Map instance to adapt as a Properties instance
143 *
144 * @return a new Properties instance backed by the supplied Map.
145 *
146 * @since 2.1.0
147 */
148 @Nonnull
149 public static Properties toProperties(@Nonnull Map<String, Object> map) {
150 requireNonNull(map, ERROR_MAP_NULL);
151 return new MapToPropertiesAdapter(map);
152 }
153
154 /**
155 * Creates a Properties instances based on the given Map.
156 *
157 * @param map the Map instance to convert as a Properties instance
158 *
159 * @return a new Properties instance based by the supplied Map.
160 *
161 * @since 2.10.0
162 */
163 @Nonnull
164 public static Properties toPropertiesDeep(@Nonnull Map<String, Object> map) {
165 requireNonNull(map, ERROR_MAP_NULL);
166 Properties properties = new Properties();
167
168 for (Map.Entry<String, Object> e : map.entrySet()) {
169 createKey(properties, e.getKey(), e.getValue());
170 }
171
172 return properties;
173 }
174
175 @SuppressWarnings("unchecked")
176 private static void createKey(@Nonnull Properties properties, @Nonnull String key, @Nonnull Object value) {
177 if (value instanceof Map) {
178 Map<String, Object> map = (Map<String, Object>) value;
179 for (Map.Entry<String, Object> e : map.entrySet()) {
180 createKey(properties, key + "." + e.getKey(), e.getValue());
181 }
182 } else {
183 properties.put(key, value);
184 }
185 }
186
187 public static class MapBuilder<K, V> implements Map<K, V> {
188 private final Map<K, V> delegate;
189
190 public MapBuilder(Map<K, V> delegate) {
191 this.delegate = delegate;
192 }
193
194 public MapBuilder<K, V> e(K k, V v) {
195 delegate.put(k, v);
196 return this;
197 }
198
199 public int size() {
200 return delegate.size();
201 }
202
203 public boolean isEmpty() {
204 return delegate.isEmpty();
205 }
206
207 public boolean containsKey(Object o) {
208 return delegate.containsKey(o);
209 }
210
211 public boolean containsValue(Object o) {
212 return delegate.containsValue(o);
213 }
214
215 public V get(Object o) {
216 return delegate.get(o);
217 }
218
219 public V put(K k, V v) {
220 return delegate.put(k, v);
221 }
222
223 public V remove(Object o) {
224 return delegate.remove(o);
225 }
226
227 public void putAll(Map<? extends K, ? extends V> map) {
228 delegate.putAll(map);
229 }
230
231 public void clear() {
232 delegate.clear();
233 }
234
235 public Set<K> keySet() {
236 return delegate.keySet();
237 }
238
239 public Collection<V> values() {
240 return delegate.values();
241 }
242
243 public Set<Entry<K, V>> entrySet() {
244 return delegate.entrySet();
245 }
246
247 @Override
248 public boolean equals(Object o) {
249 return delegate.equals(o);
250 }
251
252 @Override
253 public int hashCode() {
254 return delegate.hashCode();
255 }
256
257 @Override
258 public String toString() {
259 return delegate.toString();
260 }
261 }
262
263 public static class ListBuilder<E> implements List<E> {
264 private final List<E> delegate;
265
266 public ListBuilder(List<E> delegate) {
267 this.delegate = delegate;
268 }
269
270 public ListBuilder<E> e(E e) {
271 delegate.add(e);
272 return this;
273 }
274
275 public int size() {
276 return delegate.size();
277 }
278
279 public boolean isEmpty() {
280 return delegate.isEmpty();
281 }
282
283 public boolean contains(Object o) {
284 return delegate.contains(o);
285 }
286
287 public Iterator<E> iterator() {
288 return delegate.iterator();
289 }
290
291 public Object[] toArray() {
292 return delegate.toArray();
293 }
294
295 public <T> T[] toArray(T[] ts) {
296 return delegate.toArray(ts);
297 }
298
299 public boolean add(E e) {
300 return delegate.add(e);
301 }
302
303 public boolean remove(Object o) {
304 return delegate.remove(o);
305 }
306
307 public boolean containsAll(Collection<?> objects) {
308 return delegate.containsAll(objects);
309 }
310
311 public boolean addAll(Collection<? extends E> es) {
312 return delegate.addAll(es);
313 }
314
315 public boolean addAll(int i, Collection<? extends E> es) {
316 return delegate.addAll(i, es);
317 }
318
319 public boolean removeAll(Collection<?> objects) {
320 return delegate.removeAll(objects);
321 }
322
323 public boolean retainAll(Collection<?> objects) {
324 return delegate.retainAll(objects);
325 }
326
327 public void clear() {
328 delegate.clear();
329 }
330
331 @Override
332 public boolean equals(Object o) {
333 return delegate.equals(o);
334 }
335
336 @Override
337 public int hashCode() {
338 return delegate.hashCode();
339 }
340
341 @Override
342 public String toString() {
343 return delegate.toString();
344 }
345
346 public E get(int i) {
347 return delegate.get(i);
348 }
349
350 public E set(int i, E e) {
351 return delegate.set(i, e);
352 }
353
354 public void add(int i, E e) {
355 delegate.add(i, e);
356 }
357
358 public E remove(int i) {
359 return delegate.remove(i);
360 }
361
362 public int indexOf(Object o) {
363 return delegate.indexOf(o);
364 }
365
366 public int lastIndexOf(Object o) {
367 return delegate.lastIndexOf(o);
368 }
369
370 public ListIterator<E> listIterator() {
371 return delegate.listIterator();
372 }
373
374 public ListIterator<E> listIterator(int i) {
375 return delegate.listIterator(i);
376 }
377
378 public List<E> subList(int i, int i1) {
379 return delegate.subList(i, i1);
380 }
381 }
382
383 public static class SetBuilder<E> implements Set<E> {
384 private final Set<E> delegate;
385
386 public SetBuilder(Set<E> delegate) {
387 this.delegate = delegate;
388 }
389
390 public SetBuilder<E> e(E e) {
391 delegate.add(e);
392 return this;
393 }
394
395 public int size() {
396 return delegate.size();
397 }
398
399 public boolean isEmpty() {
400 return delegate.isEmpty();
401 }
402
403 public boolean contains(Object o) {
404 return delegate.contains(o);
405 }
406
407 public Iterator<E> iterator() {
408 return delegate.iterator();
409 }
410
411 public Object[] toArray() {
412 return delegate.toArray();
413 }
414
415 public <T> T[] toArray(T[] ts) {
416 return delegate.toArray(ts);
417 }
418
419 public boolean add(E e) {
420 return delegate.add(e);
421 }
422
423 public boolean remove(Object o) {
424 return delegate.remove(o);
425 }
426
427 public boolean containsAll(Collection<?> objects) {
428 return delegate.containsAll(objects);
429 }
430
431 public boolean addAll(Collection<? extends E> es) {
432 return delegate.addAll(es);
433 }
434
435 public boolean retainAll(Collection<?> objects) {
436 return delegate.retainAll(objects);
437 }
438
439 public boolean removeAll(Collection<?> objects) {
440 return delegate.removeAll(objects);
441 }
442
443 public void clear() {
444 delegate.clear();
445 }
446
447 @Override
448 public boolean equals(Object o) {
449 return delegate.equals(o);
450 }
451
452 @Override
453 public int hashCode() {
454 return delegate.hashCode();
455 }
456
457 @Override
458 public String toString() {
459 return delegate.toString();
460 }
461 }
462
463 private static class MapToPropertiesAdapter extends Properties {
464 private final Map<String, Object> map;
465
466 private MapToPropertiesAdapter(@Nonnull Map<String, Object> map) {
467 this.map = map;
468 }
469
470 @Override
471 public synchronized Object setProperty(String key, String value) {
472 return map.put(key, value);
473 }
474
475 @Override
476 public String getProperty(String key) {
477 Object value = map.get(key);
478 return value != null ? String.valueOf(value) : null;
479 }
480
481 @Override
482 public String getProperty(String key, String defaultValue) {
483 Object value = map.get(key);
484 return value != null ? String.valueOf(value) : defaultValue;
485 }
486
487 @Override
488 public Enumeration<?> propertyNames() {
489 return keys();
490 }
491
492 @Override
493 public Set<String> stringPropertyNames() {
494 return map.keySet();
495 }
496
497 @Override
498 public synchronized int size() {
499 return map.size();
500 }
501
502 @Override
503 public synchronized boolean isEmpty() {
504 return map.isEmpty();
505 }
506
507 @Override
508 public synchronized Enumeration<Object> keys() {
509 return new Enumeration<Object>() {
510 private Iterator<String> keys = new ArrayList<>(map.keySet()).iterator();
511
512 @Override
513 public boolean hasMoreElements() {
514 return keys.hasNext();
515 }
516
517 @Override
518 public String nextElement() {
519 return keys.next();
520 }
521 };
522 }
523
524 @Override
525 public synchronized Enumeration<Object> elements() {
526 return new Enumeration<Object>() {
527 private Iterator<Object> values = new ArrayList<>(map.values()).iterator();
528
529 @Override
530 public boolean hasMoreElements() {
531 return values.hasNext();
532 }
533
534 @Override
535 public Object nextElement() {
536 return values.next();
537 }
538 };
539 }
540
541 @Override
542 public synchronized boolean contains(Object value) {
543 return map.containsValue(value);
544 }
545
546 @Override
547 public boolean containsValue(Object value) {
548 return map.containsValue(value);
549 }
550
551 @Override
552 public synchronized boolean containsKey(Object key) {
553 return map.containsKey(key);
554 }
555
556 @Override
557 public synchronized Object get(Object key) {
558 return map.get(key);
559 }
560
561 @Override
562 public synchronized Object put(Object key, Object value) {
563 return map.put(String.valueOf(key), value);
564 }
565
566 @Override
567 public synchronized Object remove(Object key) {
568 return map.remove(key);
569 }
570
571 @Override
572 public synchronized void putAll(Map<?, ?> t) {
573 map.putAll((Map<String, Object>) t);
574 }
575
576 @Override
577 public synchronized void clear() {
578 map.clear();
579 }
580
581 @Override
582 public Set<Object> keySet() {
583 return new LinkedHashSet<Object>(map.keySet());
584 }
585
586 @Override
587 public Set<Map.Entry<Object, Object>> entrySet() {
588 Set<Map.Entry<Object, Object>> set = new LinkedHashSet<>((Set) map.entrySet());
589 return new LinkedHashSet<>(set);
590 }
591
592 @Override
593 public Collection<Object> values() {
594 return map.values();
595 }
596
597 @Override
598 public synchronized Object clone() {
599 Map<String, Object> m = new LinkedHashMap<>(map);
600 return new MapToPropertiesAdapter(m);
601 }
602 }
603 }
|