CollectionUtils.java
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 % == 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((KkeysAndValues[i](VkeysAndValues[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(valuenull;
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<>((Setmap.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 }