2 * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yangtools.yang.binding.util;
10 import com.google.common.annotations.Beta;
11 import com.google.common.collect.Collections2;
12 import com.google.common.collect.ImmutableMap;
13 import java.util.ArrayList;
14 import java.util.Arrays;
15 import java.util.Collection;
17 import java.util.Map.Entry;
18 import java.util.stream.Collector;
19 import java.util.stream.Collectors;
20 import org.eclipse.jdt.annotation.NonNull;
21 import org.opendaylight.yangtools.yang.binding.Key;
22 import org.opendaylight.yangtools.yang.binding.KeyAware;
25 * Utility class for instantiating Maps containing {@link KeyAware} values. Unlike normal Map instantiation
26 * utilities, methods in this class index values via their identifier, hence providing a more convenient API, amenable
30 * A typical example of use with generated DataObjects looks like this:
33 * Foo foo = new FooBuilder()
34 * .setBar(BindingMap.of(
35 * new BarBuilder().setName("one").build(),
36 * new BarBuilder().setName("two").build()))
42 * Another alternative is to use builders:
45 * Foo foo = new FooBuilder()
46 * .setBar(BindingMap.<BarKey, Bar>builder()
47 * .add(new BarBuilder().setName("one").build())
48 * .add(new BarBuilder().setName("two").build())
55 * This class allows for two modes of operation:
57 * <li>Unordered, available through {@link #of(KeyAware...)}/{@link #builder()} family of functions. Maps
58 * instantiated through this, preferred, interface will have their iteration order randomized, as explain in
59 * Java 9+ unmodifiable collections.</li>
60 * <li>Ordered, available through {@link #ordered(KeyAware...)}/{@link #orderedBuilder()} family of functions.
61 * Maps instantiated through this interface have a predictable iteration order, as per {@link ImmutableMap}
62 * class design. The use of this interface is generally discouraged, as it may lead to code relying on map
63 * iteration order. Nevertheless it may prove useful where the goal is to have predictable outcomes and hence
64 * is provided for completeness.</li>
68 public final class BindingMap {
69 private BindingMap() {
74 * Returns an unmodifiable map containing a single mapping.
76 * @param <K> the {@code Map}'s key type
77 * @param <V> the {@code Map}'s value type
78 * @param v1 the mapping's value
79 * @return a {@code Map} containing the specified value
80 * @throws NullPointerException if the value is {@code null}
82 public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> of(final V v1) {
83 return Map.of(v1.key(), v1);
87 * Returns an unmodifiable map containing two mappings. The resulting map is <b>NOT</b> guaranteed retain iteration
90 * @param <K> the {@code Map}'s key type
91 * @param <V> the {@code Map}'s value type
92 * @param v1 the first mapping's value
93 * @param v2 the second mapping's value
94 * @return a {@code Map} containing the specified mappings
95 * @throws IllegalArgumentException if the values contain duplicate keys
96 * @throws NullPointerException if any value is {@code null}
98 public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> of(final V v1, final V v2) {
99 return Map.of(v1.key(), v1, v2.key(), v2);
103 * Returns an unmodifiable map containing three mappings. The resulting map is <b>NOT</b> guaranteed to retain
104 * iteration order of mappings.
106 * @param <K> the {@code Map}'s key type
107 * @param <V> the {@code Map}'s value type
108 * @param v1 the first mapping's value
109 * @param v2 the second mapping's value
110 * @param v3 the third mapping's value
111 * @return a {@code Map} containing the specified mappings
112 * @throws IllegalArgumentException if the values contain duplicate keys
113 * @throws NullPointerException if any value is {@code null}
115 public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> of(final V v1, final V v2,
117 return Map.of(v1.key(), v1, v2.key(), v2, v3.key(), v3);
121 * Returns an unmodifiable map containing four mappings. The resulting map is <b>NOT</b> guaranteed to retain
122 * iteration order of mappings.
124 * @param <K> the {@code Map}'s key type
125 * @param <V> the {@code Map}'s value type
126 * @param v1 the first mapping's value
127 * @param v2 the second mapping's value
128 * @param v3 the third mapping's value
129 * @param v4 the fourth mapping's value
130 * @return a {@code Map} containing the specified mappings
131 * @throws IllegalArgumentException if the values contain duplicate keys
132 * @throws NullPointerException if any value is {@code null}
134 public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> of(final V v1, final V v2,
135 final V v3, final V v4) {
136 return Map.of(v1.key(), v1, v2.key(), v2, v3.key(), v3, v4.key(), v4);
140 * Returns an unmodifiable map containing five mappings. The resulting map is <b>NOT</b> guaranteed to retain
141 * iteration order of mappings.
143 * @param <K> the {@code Map}'s key type
144 * @param <V> the {@code Map}'s value type
145 * @param v1 the first mapping's value
146 * @param v2 the second mapping's value
147 * @param v3 the third mapping's value
148 * @param v4 the fourth mapping's value
149 * @param v5 the fifth mapping's value
150 * @return a {@code Map} containing the specified mappings
151 * @throws IllegalArgumentException if the values contain duplicate keys
152 * @throws NullPointerException if any value is {@code null}
154 public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> of(final V v1, final V v2,
155 final V v3, final V v4, final V v5) {
156 return Map.of(v1.key(), v1, v2.key(), v2, v3.key(), v3, v4.key(), v4, v5.key(), v5);
160 * Returns an unmodifiable map containing six mappings. The resulting map is <b>NOT</b> guaranteed to retain
161 * iteration order of mappings.
163 * @param <K> the {@code Map}'s key type
164 * @param <V> the {@code Map}'s value type
165 * @param v1 the first mapping's value
166 * @param v2 the second mapping's value
167 * @param v3 the third mapping's value
168 * @param v4 the fourth mapping's value
169 * @param v5 the fifth mapping's value
170 * @param v6 the sixth mapping's value
171 * @return a {@code Map} containing the specified mappings
172 * @throws IllegalArgumentException if the values contain duplicate keys
173 * @throws NullPointerException if any value is {@code null}
175 public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> of(final V v1, final V v2,
176 final V v3, final V v4, final V v5, final V v6) {
177 return Map.of(v1.key(), v1, v2.key(), v2, v3.key(), v3, v4.key(), v4, v5.key(), v5, v6.key(), v6);
181 * Returns an unmodifiable map containing seven mappings. The resulting map is <b>NOT</b> guaranteed to retain
182 * iteration order of mappings.
184 * @param <K> the {@code Map}'s key type
185 * @param <V> the {@code Map}'s value type
186 * @param v1 the first mapping's value
187 * @param v2 the second mapping's value
188 * @param v3 the third mapping's value
189 * @param v4 the fourth mapping's value
190 * @param v5 the fifth mapping's value
191 * @param v6 the sixth mapping's value
192 * @param v7 the seventh mapping's value
193 * @return a {@code Map} containing the specified mappings
194 * @throws IllegalArgumentException if the values contain duplicate keys
195 * @throws NullPointerException if any value is {@code null}
197 public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> of(final V v1, final V v2,
198 final V v3, final V v4, final V v5, final V v6, final V v7) {
199 return Map.of(v1.key(), v1, v2.key(), v2, v3.key(), v3, v4.key(), v4, v5.key(), v5, v6.key(), v6, v7.key(), v7);
203 * Returns an unmodifiable map containing eight mappings. The resulting map is <b>NOT</b> guaranteed to retain
204 * iteration order of mappings.
206 * @param <K> the {@code Map}'s key type
207 * @param <V> the {@code Map}'s value type
208 * @param v1 the first mapping's value
209 * @param v2 the second mapping's value
210 * @param v3 the third mapping's value
211 * @param v4 the fourth mapping's value
212 * @param v5 the fifth mapping's value
213 * @param v6 the sixth mapping's value
214 * @param v7 the seventh mapping's value
215 * @param v8 the eighth mapping's value
216 * @return a {@code Map} containing the specified mappings
217 * @throws IllegalArgumentException if the values contain duplicate keys
218 * @throws NullPointerException if any value is {@code null}
220 public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> of(final V v1, final V v2,
221 final V v3, final V v4, final V v5, final V v6, final V v7, final V v8) {
222 return Map.of(v1.key(), v1, v2.key(), v2, v3.key(), v3, v4.key(), v4, v5.key(), v5, v6.key(), v6, v7.key(), v7,
227 * Returns an unmodifiable map containing nine mappings. The resulting map is <b>NOT</b> guaranteed to retain
228 * iteration order of mappings.
230 * @param <K> the {@code Map}'s key type
231 * @param <V> the {@code Map}'s value type
232 * @param v1 the first mapping's value
233 * @param v2 the second mapping's value
234 * @param v3 the third mapping's value
235 * @param v4 the fourth mapping's value
236 * @param v5 the fifth mapping's value
237 * @param v6 the sixth mapping's value
238 * @param v7 the seventh mapping's value
239 * @param v8 the eighth mapping's value
240 * @param v9 the ninth mapping's value
241 * @return a {@code Map} containing the specified mappings
242 * @throws IllegalArgumentException if the values contain duplicate keys
243 * @throws NullPointerException if any value is {@code null}
245 public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> of(final V v1, final V v2,
246 final V v3, final V v4, final V v5, final V v6, final V v7, final V v8, final V v9) {
247 return Map.of(v1.key(), v1, v2.key(), v2, v3.key(), v3, v4.key(), v4, v5.key(), v5, v6.key(), v6, v7.key(), v7,
248 v8.key(), v8, v9.key(), v9);
252 * Returns an unmodifiable map containing ten mappings. The resulting map is <b>NOT</b> guaranteed to retain
253 * iteration order of mappings.
255 * @param <K> the {@code Map}'s key type
256 * @param <V> the {@code Map}'s value type
257 * @param v1 the first mapping's value
258 * @param v2 the second mapping's value
259 * @param v3 the third mapping's value
260 * @param v4 the fourth mapping's value
261 * @param v5 the fifth mapping's value
262 * @param v6 the sixth mapping's value
263 * @param v7 the seventh mapping's value
264 * @param v8 the eighth mapping's value
265 * @param v9 the ninth mapping's value
266 * @param v10 the ninth mapping's value
267 * @return a {@code Map} containing the specified mappings
268 * @throws IllegalArgumentException if the values contain duplicate keys
269 * @throws NullPointerException if any value is {@code null}
271 public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> of(final V v1, final V v2,
272 final V v3, final V v4, final V v5, final V v6, final V v7, final V v8, final V v9, final V v10) {
273 return Map.of(v1.key(), v1, v2.key(), v2, v3.key(), v3, v4.key(), v4, v5.key(), v5, v6.key(), v6, v7.key(), v7,
274 v8.key(), v8, v9.key(), v9, v10.key(), v10);
278 * Returns an unmodifiable map containing given values. The resulting map is <b>NOT</b> guaranteed to retain
279 * iteration order of the input array.
281 * @param <K> the {@code Map}'s key type
282 * @param <V> the {@code Map}'s value type
283 * @param values values from which the map is populated
284 * @return a {@code Map} containing the specified values
285 * @throws IllegalArgumentException if there are any duplicate keys in the provided values
286 * @throws NullPointerException if any value is {@code null}, or if the {@code values} array is {@code null}
289 public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> of(final V... values) {
290 return of(Arrays.asList(values));
294 * Returns an unmodifiable map containing given values. The resulting map is <b>NOT</b> guaranteed to retain
295 * iteration order of the input collection.
297 * @param <K> the {@code Map}'s key type
298 * @param <V> the {@code Map}'s value type
299 * @param values values from which the map is populated
300 * @return a {@code Map} containing the specified values
301 * @throws IllegalArgumentException if there are any duplicate keys in the provided values
302 * @throws NullPointerException if any value is {@code null}, or if the {@code values} array is {@code null}
304 public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> of(
305 final Collection<V> values) {
306 return values.stream().collect(toMap());
310 * Returns a collector which collects binding {@link KeyAware} objects into an unmodifiable map. The resulting
311 * map is <b>NOT</b> guaranteed to retain iteration order of the stream it collects.
313 * @param <K> the {@code Map}'s key type
314 * @param <V> the {@code Map}'s value type
315 * @return A collector that accumulates the input elements into an unmodifiable map.
317 public static <K extends Key<V>, V extends KeyAware<K>>
318 @NonNull Collector<V, ?, ? extends Map<K, V>> toMap() {
319 return Collectors.toUnmodifiableMap(KeyAware::key, v -> v);
323 * Create a builder on an unmodifiable map, which does not retain value insertion order. The builder will be
324 * pre-sized to hold {@value Builder#DEFAULT_INITIAL_CAPACITY} elements.
326 * @param <K> the {@code Map}'s key type
327 * @param <V> the {@code Map}'s value type
328 * @return A {@link Builder} instance.
330 public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Builder<K, V> builder() {
331 return builder(Builder.DEFAULT_INITIAL_CAPACITY);
335 * Create a builder on an unmodifiable map, which does not retain value insertion order. The builder will be
336 * pre-sized to hold specified number of elements.
338 * @param <K> the {@code Map}'s key type
339 * @param <V> the {@code Map}'s value type
340 * @param expectedSize Expected number of values in the resulting map
341 * @return A {@link Builder} instance.
343 public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Builder<K, V> builder(
344 final int expectedSize) {
345 return new UnorderedBuilder<>(expectedSize);
349 * Returns an unmodifiable map containing two mappings. The resulting map will retain iteration order of mappings.
351 * @param <K> the {@code Map}'s key type
352 * @param <V> the {@code Map}'s value type
353 * @param v1 the first mapping's value
354 * @param v2 the second mapping's value
355 * @return a {@code Map} containing the specified mappings
356 * @throws IllegalArgumentException if the values contain duplicate keys
357 * @throws NullPointerException if any value is {@code null}
359 public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> ordered(final V v1,
361 return ImmutableMap.of(v1.key(), v1, v2.key(), v2);
365 * Returns an unmodifiable map containing three mappings. The resulting map will retain iteration order of mappings.
367 * @param <K> the {@code Map}'s key type
368 * @param <V> the {@code Map}'s value type
369 * @param v1 the first mapping's value
370 * @param v2 the second mapping's value
371 * @param v3 the third mapping's value
372 * @return a {@code Map} containing the specified mappings
373 * @throws IllegalArgumentException if the values contain duplicate keys
374 * @throws NullPointerException if any value is {@code null}
376 public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> ordered(final V v1,
377 final V v2, final V v3) {
378 return ImmutableMap.of(v1.key(), v1, v2.key(), v2, v3.key(), v3);
382 * Returns an unmodifiable map containing four mappings. The resulting map will retain iteration order of mappings.
384 * @param <K> the {@code Map}'s key type
385 * @param <V> the {@code Map}'s value type
386 * @param v1 the first mapping's value
387 * @param v2 the second mapping's value
388 * @param v3 the third mapping's value
389 * @param v4 the fourth mapping's value
390 * @return a {@code Map} containing the specified mappings
391 * @throws IllegalArgumentException if the values contain duplicate keys
392 * @throws NullPointerException if any value is {@code null}
394 public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> ordered(final V v1,
395 final V v2, final V v3, final V v4) {
396 return ImmutableMap.of(v1.key(), v1, v2.key(), v2, v3.key(), v3, v4.key(), v4);
400 * Returns an unmodifiable map containing five mappings. The resulting map will retain iteration order of mappings.
402 * @param <K> the {@code Map}'s key type
403 * @param <V> the {@code Map}'s value type
404 * @param v1 the first mapping's value
405 * @param v2 the second mapping's value
406 * @param v3 the third mapping's value
407 * @param v4 the fourth mapping's value
408 * @param v5 the fifth mapping's value
409 * @return a {@code Map} containing the specified mappings
410 * @throws IllegalArgumentException if the values contain duplicate keys
411 * @throws NullPointerException if any value is {@code null}
413 public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> ordered(final V v1,
414 final V v2, final V v3, final V v4, final V v5) {
415 return ImmutableMap.of(v1.key(), v1, v2.key(), v2, v3.key(), v3, v4.key(), v4, v5.key(), v5);
419 * Returns an unmodifiable map containing given values. Resulting {@code Map} will retain the iteration order of
422 * @param <K> the {@code Map}'s key type
423 * @param <V> the {@code Map}'s value type
424 * @param values values from which the map is populated
425 * @return a {@code Map} containing the specified values
426 * @throws IllegalArgumentException if there are any duplicate keys in the provided values
427 * @throws NullPointerException if any value is {@code null}, or if the {@code values} array is {@code null}
430 public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> ordered(final V... values) {
431 return ordered(Arrays.asList(values));
435 * Returns an unmodifiable map containing given values. Resulting {@code Map} will retain the iteration order of
438 * @param <K> the {@code Map}'s key type
439 * @param <V> the {@code Map}'s value type
440 * @param values values from which the map is populated
441 * @return a {@code Map} containing the specified values
442 * @throws IllegalArgumentException if there are any duplicate keys in the provided values
443 * @throws NullPointerException if any value is {@code null}, or if the {@code values} array is {@code null}
445 public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Map<K, V> ordered(
446 final Collection<V> values) {
447 return values.stream().collect(toOrderedMap());
451 * Returns a collector which collects binding {@link KeyAware} objects into an unmodifiable map. The resulting
452 * map will retain iteration order of the stream it collects.
454 * @param <K> the {@code Map}'s key type
455 * @param <V> the {@code Map}'s value type
456 * @return A collector that accumulates the input elements into an unmodifiable map.
458 public static <K extends Key<V>, V extends KeyAware<K>>
459 @NonNull Collector<V, ?, ? extends Map<K, V>> toOrderedMap() {
460 return ImmutableMap.<V, K, V>toImmutableMap(KeyAware::key, v -> v);
464 * Create a builder on an unmodifiable map, which retains value insertion order. The builder will be pre-sized to
465 * hold {@value Builder#DEFAULT_INITIAL_CAPACITY} elements.
467 * @param <K> the {@code Map}'s key type
468 * @param <V> the {@code Map}'s value type
469 * @return A {@link Builder} instance.
471 public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Builder<K, V> orderedBuilder() {
472 return orderedBuilder(Builder.DEFAULT_INITIAL_CAPACITY);
476 * Create a builder on an unmodifiable map, which retains value insertion order. The builder will be pre-sized to
477 * hold specified number of elements.
479 * @param <K> the {@code Map}'s key type
480 * @param <V> the {@code Map}'s value type
481 * @param expectedSize Expected number of values in the resulting map
482 * @return A {@link Builder} instance.
484 public static <K extends Key<V>, V extends KeyAware<K>> @NonNull Builder<K, V> orderedBuilder(
485 final int expectedSize) {
486 return new OrderedBuilder<>(expectedSize);
490 * Builder producing a Map containing binding {@link KeyAware} values.
492 * @param <K> the {@code Map}'s key type
493 * @param <V> the {@code Map}'s value type
495 public abstract static class Builder<K extends Key<V>, V extends KeyAware<K>> {
496 static final int DEFAULT_INITIAL_CAPACITY = 4;
503 * Add a value to this builder.
505 * @param value the value to add
506 * @return this builder
507 * @throws NullPointerException if value is {@code null}
509 public final @NonNull Builder<K, V> add(final V value) {
510 addEntry(value.key(), value);
515 * Add values to this builder.
517 * @param values the values to add
518 * @return this builder
519 * @throws NullPointerException if value is, or contains, {@code null}
522 public final @NonNull Builder<K, V> addAll(final V... values) {
523 return addAll(Arrays.asList(values));
527 * Add values to this builder.
529 * @param values the values to add
530 * @return this builder
531 * @throws NullPointerException if value is, or contains, {@code null}
533 public final @NonNull Builder<K, V> addAll(final Collection<V> values) {
534 addEntries(Collections2.transform(values, value -> Map.entry(value.key(), value)));
539 * Build map from existing map entries in this builder.
541 * @return Resulting map
542 * @throws IllegalArgumentException if duplicate keys were added
544 public abstract @NonNull Map<K, V> build();
547 * Add map entry identified by its {@code key} and containing {@code value} to this builder.
549 * @param key Key of the map entry
550 * @param value Value of the map entry
552 abstract void addEntry(K key, V value);
555 * Add collection of map entries to this builder.
557 * @param entries Map entries to add
559 abstract void addEntries(Collection<Entry<K, V>> entries);
562 private static final class OrderedBuilder<K extends Key<V>, V extends KeyAware<K>>
563 extends Builder<K, V> {
564 private final ImmutableMap.Builder<K, V> delegate;
566 OrderedBuilder(final int expectedSize) {
567 delegate = ImmutableMap.builderWithExpectedSize(expectedSize);
571 public Map<K, V> build() {
572 return delegate.build();
576 void addEntry(final K key, final V value) {
577 delegate.put(key, value);
581 void addEntries(final Collection<Entry<K, V>> entries) {
582 delegate.putAll(entries);
586 private static final class UnorderedBuilder<K extends Key<V>, V extends KeyAware<K>>
587 extends Builder<K, V> {
588 private final ArrayList<Entry<K, V>> buffer;
590 UnorderedBuilder(final int expectedSize) {
591 buffer = new ArrayList<>(expectedSize);
595 @SuppressWarnings("unchecked")
596 public Map<K, V> build() {
597 return Map.ofEntries(buffer.toArray(new Entry[0]));
601 void addEntry(final K key, final V value) {
602 buffer.add(Map.entry(key, value));
606 void addEntries(final Collection<Entry<K, V>> entries) {
607 buffer.addAll(entries);