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        
168        @Override
169        public Builder<K, V> put(K key, V value) {
170          super.put(key, value);
171          return this;
172        }
173    
174        /**
175         * {@inheritDoc}
176         *
177         * @since 11.0
178         */
179        
180        @Override
181        public Builder<K, V> put(
182            Entry<? extends K, ? extends V> entry) {
183          super.put(entry);
184          return this;
185        }
186    
187        
188        @Override
189        public Builder<K, V> putAll(K key, Iterable<? extends V> values) {
190          super.putAll(key, values);
191          return this;
192        }
193    
194        
195        @Override
196        public Builder<K, V> putAll(K key, V... values) {
197          super.putAll(key, values);
198          return this;
199        }
200    
201        
202        @Override
203        public Builder<K, V> putAll(
204            Multimap<? extends K, ? extends V> multimap) {
205          super.putAll(multimap);
206          return this;
207        }
208    
209        /**
210         * {@inheritDoc}
211         *
212         * @since 8.0
213         */
214        @Beta @Override
215        public Builder<K, V> orderKeysBy(Comparator<? super K> keyComparator) {
216          super.orderKeysBy(keyComparator);
217          return this;
218        }
219    
220        /**
221         * {@inheritDoc}
222         *
223         * @since 8.0
224         */
225        @Beta @Override
226        public Builder<K, V> orderValuesBy(Comparator<? super V> valueComparator) {
227          super.orderValuesBy(valueComparator);
228          return this;
229        }
230    
231        /**
232         * Returns a newly-created immutable list multimap.
233         */
234        
235        @Override
236        public ImmutableListMultimap<K, V> build() {
237          return (ImmutableListMultimap<K, V>) super.build();
238        }
239      }
240    
241      /**
242       * Returns an immutable multimap containing the same mappings as {@code
243       * multimap}. The generated multimap's key and value orderings correspond to
244       * the iteration ordering of the {@code multimap.asMap()} view.
245       *
246       * <p>Despite the method name, this method attempts to avoid actually copying
247       * the data when it is safe to do so. The exact circumstances under which a
248       * copy will or will not be performed are undocumented and subject to change.
249       *
250       * @throws NullPointerException if any key or value in {@code multimap} is
251       *         null
252       */
253      public static <K, V> ImmutableListMultimap<K, V> copyOf(
254          Multimap<? extends K, ? extends V> multimap) {
255        if (multimap.isEmpty()) {
256          return of();
257        }
258    
259        // TODO(user): copy ImmutableSetMultimap by using asList() on the sets
260        if (multimap instanceof ImmutableListMultimap) {
261          @SuppressWarnings("unchecked") // safe since multimap is not writable
262          ImmutableListMultimap<K, V> kvMultimap
263              = (ImmutableListMultimap<K, V>) multimap;
264          if (!kvMultimap.isPartialView()) {
265            return kvMultimap;
266          }
267        }
268    
269        ImmutableMap.Builder<K, ImmutableList<V>> builder = ImmutableMap.builder();
270        int size = 0;
271    
272        for (Entry<? extends K, ? extends Collection<? extends V>> entry
273            : multimap.asMap().entrySet()) {
274          ImmutableList<V> list = ImmutableList.copyOf(entry.getValue());
275          if (!list.isEmpty()) {
276            builder.put(entry.getKey(), list);
277            size += list.size();
278          }
279        }
280    
281        return new ImmutableListMultimap<K, V>(builder.build(), size);
282      }
283    
284      ImmutableListMultimap(ImmutableMap<K, ImmutableList<V>> map, int size) {
285        super(map, size);
286      }
287    
288      // views
289    
290      /**
291       * Returns an immutable list of the values for the given key.  If no mappings
292       * in the multimap have the provided key, an empty immutable list is
293       * returned. The values are in the same order as the parameters used to build
294       * this multimap.
295       */
296      
297      @Override
298      public ImmutableList<V> get(@Nullable K key) {
299        // This cast is safe as its type is known in constructor.
300        ImmutableList<V> list = (ImmutableList<V>) map.get(key);
301        return (list == null) ? ImmutableList.<V>of() : list;
302      }
303    
304      private transient ImmutableListMultimap<V, K> inverse;
305    
306      /**
307       * {@inheritDoc}
308       *
309       * <p>Because an inverse of a list multimap can contain multiple pairs with
310       * the same key and value, this method returns an {@code
311       * ImmutableListMultimap} rather than the {@code ImmutableMultimap} specified
312       * in the {@code ImmutableMultimap} class.
313       *
314       * @since 11
315       */
316      
317      @Override
318      @Beta
319      public ImmutableListMultimap<V, K> inverse() {
320        ImmutableListMultimap<V, K> result = inverse;
321        return (result == null) ? (inverse = invert()) : result;
322      }
323    
324      private ImmutableListMultimap<V, K> invert() {
325        Builder<V, K> builder = builder();
326        for (Entry<K, V> entry : entries()) {
327          builder.put(entry.getValue(), entry.getKey());
328        }
329        ImmutableListMultimap<V, K> invertedMultimap = builder.build();
330        invertedMultimap.inverse = this;
331        return invertedMultimap;
332      }
333    
334      /**
335       * Guaranteed to throw an exception and leave the multimap unmodified.
336       *
337       * @throws UnsupportedOperationException always
338       */
339      
340      @Override
341      public ImmutableList<V> removeAll(Object key) {
342        throw new UnsupportedOperationException();
343      }
344    
345      /**
346       * Guaranteed to throw an exception and leave the multimap unmodified.
347       *
348       * @throws UnsupportedOperationException always
349       */
350      
351      @Override
352      public ImmutableList<V> replaceValues(
353          K key, Iterable<? extends V> values) {
354        throw new UnsupportedOperationException();
355      }
356    
357      /**
358       * @serialData number of distinct keys, and then for each distinct key: the
359       *     key, the number of values for that key, and the key's values
360       */
361      @GwtIncompatible("java.io.ObjectOutputStream")
362      private void writeObject(ObjectOutputStream stream) throws IOException {
363        stream.defaultWriteObject();
364        Serialization.writeMultimap(this, stream);
365      }
366    
367      @GwtIncompatible("java.io.ObjectInputStream")
368      private void readObject(ObjectInputStream stream)
369          throws IOException, ClassNotFoundException {
370        stream.defaultReadObject();
371        int keyCount = stream.readInt();
372        if (keyCount < 0) {
373          throw new InvalidObjectException("Invalid key count " + keyCount);
374        }
375        ImmutableMap.Builder<Object, ImmutableList<Object>> builder
376            = ImmutableMap.builder();
377        int tmpSize = 0;
378    
379        for (int i = 0; i < keyCount; i++) {
380          Object key = stream.readObject();
381          int valueCount = stream.readInt();
382          if (valueCount <= 0) {
383            throw new InvalidObjectException("Invalid value count " + valueCount);
384          }
385    
386          Object[] array = new Object[valueCount];
387          for (int j = 0; j < valueCount; j++) {
388            array[j] = stream.readObject();
389          }
390          builder.put(key, ImmutableList.copyOf(array));
391          tmpSize += valueCount;
392        }
393    
394        ImmutableMap<Object, ImmutableList<Object>> tmpMap;
395        try {
396          tmpMap = builder.build();
397        } catch (IllegalArgumentException e) {
398          throw (InvalidObjectException)
399              new InvalidObjectException(e.getMessage()).initCause(e);
400        }
401    
402        FieldSettersHolder.MAP_FIELD_SETTER.set(this, tmpMap);
403        FieldSettersHolder.SIZE_FIELD_SETTER.set(this, tmpSize);
404      }
405    
406      @GwtIncompatible("Not needed in emulated source")
407      private static final long serialVersionUID = 0;
408    }