001    /*
002     * Copyright (C) 2008 The Guava 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    
017    package com.google.common.collect;
018    
019    import com.google.common.annotations.Beta;
020    import com.google.common.annotations.GwtCompatible;
021    import com.google.common.annotations.GwtIncompatible;
022    
023    import java.io.IOException;
024    import java.io.InvalidObjectException;
025    import java.io.ObjectInputStream;
026    import java.io.ObjectOutputStream;
027    import java.util.Collection;
028    import java.util.Comparator;
029    import java.util.Map.Entry;
030    
031    import javax.annotation.Nullable;
032    
033    /**
034     * An immutable {@link ListMultimap} with reliable user-specified key and value
035     * iteration order. Does not permit null keys or values.
036     *
037     * <p>Unlike {@link Multimaps#unmodifiableListMultimap(ListMultimap)}, which is
038     * a <i>view</i> of a separate multimap which can still change, an instance of
039     * {@code ImmutableListMultimap} contains its own data and will <i>never</i>
040     * change. {@code ImmutableListMultimap} is convenient for
041     * {@code public static final} multimaps ("constant multimaps") and also lets
042     * you easily make a "defensive copy" of a multimap provided to your class by
043     * a caller.
044     *
045     * <p><b>Note:</b> Although this class is not final, it cannot be subclassed as
046     * it has no public or protected constructors. Thus, instances of this class
047     * are guaranteed to be immutable.
048     *
049     * <p>See the Guava User Guide article on <a href=
050     * "http://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained">
051     * immutable collections</a>.
052     *
053     * @author Jared Levy
054     * @since 2.0 (imported from Google Collections Library)
055     */
056    @GwtCompatible(serializable = true, emulated = true)
057    public class ImmutableListMultimap<K, V>
058        extends ImmutableMultimap<K, V>
059        implements ListMultimap<K, V> {
060    
061      /** Returns the empty multimap. */
062      // Casting is safe because the multimap will never hold any elements.
063      @SuppressWarnings("unchecked")
064      public static <K, V> ImmutableListMultimap<K, V> of() {
065        return (ImmutableListMultimap<K, V>) EmptyImmutableListMultimap.INSTANCE;
066      }
067    
068      /**
069       * Returns an immutable multimap containing a single entry.
070       */
071      public static <K, V> ImmutableListMultimap<K, V> of(K k1, V v1) {
072        ImmutableListMultimap.Builder<K, V> builder
073            = ImmutableListMultimap.builder();
074        builder.put(k1, v1);
075        return builder.build();
076      }
077    
078      /**
079       * Returns an immutable multimap containing the given entries, in order.
080       */
081      public static <K, V> ImmutableListMultimap<K, V> of(K k1, V v1, K k2, V v2) {
082        ImmutableListMultimap.Builder<K, V> builder
083            = ImmutableListMultimap.builder();
084        builder.put(k1, v1);
085        builder.put(k2, v2);
086        return builder.build();
087      }
088    
089      /**
090       * Returns an immutable multimap containing the given entries, in order.
091       */
092      public static <K, V> ImmutableListMultimap<K, V> of(
093          K k1, V v1, K k2, V v2, K k3, V v3) {
094        ImmutableListMultimap.Builder<K, V> builder
095            = ImmutableListMultimap.builder();
096        builder.put(k1, v1);
097        builder.put(k2, v2);
098        builder.put(k3, v3);
099        return builder.build();
100      }
101    
102      /**
103       * Returns an immutable multimap containing the given entries, in order.
104       */
105      public static <K, V> ImmutableListMultimap<K, V> of(
106          K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
107        ImmutableListMultimap.Builder<K, V> builder
108            = ImmutableListMultimap.builder();
109        builder.put(k1, v1);
110        builder.put(k2, v2);
111        builder.put(k3, v3);
112        builder.put(k4, v4);
113        return builder.build();
114      }
115    
116      /**
117       * Returns an immutable multimap containing the given entries, in order.
118       */
119      public static <K, V> ImmutableListMultimap<K, V> of(
120          K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
121        ImmutableListMultimap.Builder<K, V> builder
122            = ImmutableListMultimap.builder();
123        builder.put(k1, v1);
124        builder.put(k2, v2);
125        builder.put(k3, v3);
126        builder.put(k4, v4);
127        builder.put(k5, v5);
128        return builder.build();
129      }
130    
131      // looking for of() with > 5 entries? Use the builder instead.
132    
133      /**
134       * Returns a new builder. The generated builder is equivalent to the builder
135       * created by the {@link Builder} constructor.
136       */
137      public static <K, V> Builder<K, V> builder() {
138        return new Builder<K, V>();
139      }
140    
141      /**
142       * A builder for creating immutable {@code ListMultimap} instances, especially
143       * {@code public static final} multimaps ("constant multimaps"). Example:
144       * <pre>   {@code
145       *
146       *   static final Multimap<String, Integer> STRING_TO_INTEGER_MULTIMAP =
147       *       new ImmutableListMultimap.Builder<String, Integer>()
148       *           .put("one", 1)
149       *           .putAll("several", 1, 2, 3)
150       *           .putAll("many", 1, 2, 3, 4, 5)
151       *           .build();}</pre>
152       *
153       * Builder instances can be reused; it is safe to call {@link #build} multiple
154       * times to build multiple multimaps in series. Each multimap contains the
155       * key-value mappings in the previously created multimaps.
156       *
157       * @since 2.0 (imported from Google Collections Library)
158       */
159      public static final class Builder<K, V>
160          extends ImmutableMultimap.Builder<K, V> {
161        /**
162         * Creates a new builder. The returned builder is equivalent to the builder
163         * generated by {@link ImmutableListMultimap#builder}.
164         */
165        public Builder() {}
166    
167        @Override public Builder<K, V> put(K key, V value) {
168          super.put(key, value);
169          return this;
170        }
171    
172        /**
173         * {@inheritDoc}
174         *
175         * @since 11.0
176         */
177        @Override public Builder<K, V> put(
178            Entry<? extends K, ? extends V> entry) {
179          super.put(entry);
180          return this;
181        }
182    
183        @Override public Builder<K, V> putAll(K key, Iterable<? extends V> values) {
184          super.putAll(key, values);
185          return this;
186        }
187    
188        @Override public Builder<K, V> putAll(K key, V... values) {
189          super.putAll(key, values);
190          return this;
191        }
192    
193        @Override public Builder<K, V> putAll(
194            Multimap<? extends K, ? extends V> multimap) {
195          super.putAll(multimap);
196          return this;
197        }
198    
199        /**
200         * {@inheritDoc}
201         *
202         * @since 8.0
203         */
204        @Beta @Override
205        public Builder<K, V> orderKeysBy(Comparator<? super K> keyComparator) {
206          super.orderKeysBy(keyComparator);
207          return this;
208        }
209    
210        /**
211         * {@inheritDoc}
212         *
213         * @since 8.0
214         */
215        @Beta @Override
216        public Builder<K, V> orderValuesBy(Comparator<? super V> valueComparator) {
217          super.orderValuesBy(valueComparator);
218          return this;
219        }
220    
221        /**
222         * Returns a newly-created immutable list multimap.
223         */
224        @Override public ImmutableListMultimap<K, V> build() {
225          return (ImmutableListMultimap<K, V>) super.build();
226        }
227      }
228    
229      /**
230       * Returns an immutable multimap containing the same mappings as {@code
231       * multimap}. The generated multimap's key and value orderings correspond to
232       * the iteration ordering of the {@code multimap.asMap()} view.
233       *
234       * <p>Despite the method name, this method attempts to avoid actually copying
235       * the data when it is safe to do so. The exact circumstances under which a
236       * copy will or will not be performed are undocumented and subject to change.
237       *
238       * @throws NullPointerException if any key or value in {@code multimap} is
239       *         null
240       */
241      public static <K, V> ImmutableListMultimap<K, V> copyOf(
242          Multimap<? extends K, ? extends V> multimap) {
243        if (multimap.isEmpty()) {
244          return of();
245        }
246    
247        // TODO(user): copy ImmutableSetMultimap by using asList() on the sets
248        if (multimap instanceof ImmutableListMultimap) {
249          @SuppressWarnings("unchecked") // safe since multimap is not writable
250          ImmutableListMultimap<K, V> kvMultimap
251              = (ImmutableListMultimap<K, V>) multimap;
252          if (!kvMultimap.isPartialView()) {
253            return kvMultimap;
254          }
255        }
256    
257        ImmutableMap.Builder<K, ImmutableList<V>> builder = ImmutableMap.builder();
258        int size = 0;
259    
260        for (Entry<? extends K, ? extends Collection<? extends V>> entry
261            : multimap.asMap().entrySet()) {
262          ImmutableList<V> list = ImmutableList.copyOf(entry.getValue());
263          if (!list.isEmpty()) {
264            builder.put(entry.getKey(), list);
265            size += list.size();
266          }
267        }
268    
269        return new ImmutableListMultimap<K, V>(builder.build(), size);
270      }
271    
272      ImmutableListMultimap(ImmutableMap<K, ImmutableList<V>> map, int size) {
273        super(map, size);
274      }
275    
276      // views
277    
278      /**
279       * Returns an immutable list of the values for the given key.  If no mappings
280       * in the multimap have the provided key, an empty immutable list is
281       * returned. The values are in the same order as the parameters used to build
282       * this multimap.
283       */
284      @Override public ImmutableList<V> get(@Nullable K key) {
285        // This cast is safe as its type is known in constructor.
286        ImmutableList<V> list = (ImmutableList<V>) map.get(key);
287        return (list == null) ? ImmutableList.<V>of() : list;
288      }
289    
290      private transient ImmutableListMultimap<V, K> inverse;
291    
292      /**
293       * {@inheritDoc}
294       *
295       * <p>Because an inverse of a list multimap can contain multiple pairs with the same key and
296       * value, this method returns an {@code ImmutableListMultimap} rather than the
297       * {@code ImmutableMultimap} specified in the {@code ImmutableMultimap} class.
298       *
299       * @since 11
300       */
301      @Beta
302      public ImmutableListMultimap<V, K> inverse() {
303        ImmutableListMultimap<V, K> result = inverse;
304        return (result == null) ? (inverse = invert()) : result;
305      }
306    
307      private ImmutableListMultimap<V, K> invert() {
308        Builder<V, K> builder = builder();
309        for (Entry<K, V> entry : entries()) {
310          builder.put(entry.getValue(), entry.getKey());
311        }
312        ImmutableListMultimap<V, K> invertedMultimap = builder.build();
313        invertedMultimap.inverse = this;
314        return invertedMultimap;
315      }
316    
317      /**
318       * Guaranteed to throw an exception and leave the multimap unmodified.
319       *
320       * @throws UnsupportedOperationException always
321       */
322      @Override public ImmutableList<V> removeAll(Object key) {
323        throw new UnsupportedOperationException();
324      }
325    
326      /**
327       * Guaranteed to throw an exception and leave the multimap unmodified.
328       *
329       * @throws UnsupportedOperationException always
330       */
331      @Override public ImmutableList<V> replaceValues(
332          K key, Iterable<? extends V> values) {
333        throw new UnsupportedOperationException();
334      }
335    
336      /**
337       * @serialData number of distinct keys, and then for each distinct key: the
338       *     key, the number of values for that key, and the key's values
339       */
340      @GwtIncompatible("java.io.ObjectOutputStream")
341      private void writeObject(ObjectOutputStream stream) throws IOException {
342        stream.defaultWriteObject();
343        Serialization.writeMultimap(this, stream);
344      }
345    
346      @GwtIncompatible("java.io.ObjectInputStream")
347      private void readObject(ObjectInputStream stream)
348          throws IOException, ClassNotFoundException {
349        stream.defaultReadObject();
350        int keyCount = stream.readInt();
351        if (keyCount < 0) {
352          throw new InvalidObjectException("Invalid key count " + keyCount);
353        }
354        ImmutableMap.Builder<Object, ImmutableList<Object>> builder
355            = ImmutableMap.builder();
356        int tmpSize = 0;
357    
358        for (int i = 0; i < keyCount; i++) {
359          Object key = stream.readObject();
360          int valueCount = stream.readInt();
361          if (valueCount <= 0) {
362            throw new InvalidObjectException("Invalid value count " + valueCount);
363          }
364    
365          Object[] array = new Object[valueCount];
366          for (int j = 0; j < valueCount; j++) {
367            array[j] = stream.readObject();
368          }
369          builder.put(key, ImmutableList.copyOf(array));
370          tmpSize += valueCount;
371        }
372    
373        ImmutableMap<Object, ImmutableList<Object>> tmpMap;
374        try {
375          tmpMap = builder.build();
376        } catch (IllegalArgumentException e) {
377          throw (InvalidObjectException)
378              new InvalidObjectException(e.getMessage()).initCause(e);
379        }
380    
381        FieldSettersHolder.MAP_FIELD_SETTER.set(this, tmpMap);
382        FieldSettersHolder.SIZE_FIELD_SETTER.set(this, tmpSize);
383      }
384    
385      @GwtIncompatible("Not needed in emulated source")
386      private static final long serialVersionUID = 0;
387    }