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