/*
 * Copyright (C) 2007 The Guava Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.glassfish.jersey.internal.guava;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.AbstractCollection;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Supplier;

import static org.glassfish.jersey.internal.guava.Preconditions.checkNotNull;

Provides static methods acting on or generating a Multimap.

See the Guava User Guide article on Multimaps.

Author:Jared Levy, Robert Konigsberg, Mike Bostock, Louis Wasserman
Since:2.0 (imported from Google Collections Library)
/** * Provides static methods acting on or generating a {@code Multimap}. * <p> * <p>See the Guava User Guide article on <a href= * "http://code.google.com/p/guava-libraries/wiki/CollectionUtilitiesExplained#Multimaps"> * {@code Multimaps}</a>. * * @author Jared Levy * @author Robert Konigsberg * @author Mike Bostock * @author Louis Wasserman * @since 2.0 (imported from Google Collections Library) */
public final class Multimaps { private Multimaps() { }
Creates a new ListMultimap that uses the provided map and factory. It can generate a multimap based on arbitrary Map and List classes.

The factory-generated and map classes determine the multimap iteration order. They also specify the behavior of the equals, hashCode, and toString methods for the multimap and its returned views. The multimap's get, removeAll, and replaceValues methods return RandomAccess lists if the factory does. However, the multimap's get method returns instances of a different class than does factory.get().

The multimap is serializable if map, factory, the lists generated by factory, and the multimap contents are all serializable.

The multimap is not threadsafe when any concurrent operations update the multimap, even if map and the instances generated by factory are. Concurrent read operations will work correctly. To allow concurrent update operations, wrap the multimap with a call to synchronizedListMultimap.

Call this method only when the simpler methods create.create() and create.create() won't suffice.

Note: the multimap assumes complete ownership over of map and the lists returned by factory. Those objects should not be manually updated, they should be empty when provided, and they should not use soft, weak, or phantom references.

Params:
  • map – place to store the mapping from each key to its corresponding values
  • factory – supplier of new, empty lists that will each hold all values for a given key
Throws:
/** * Creates a new {@code ListMultimap} that uses the provided map and factory. * It can generate a multimap based on arbitrary {@link Map} and {@link List} * classes. * <p> * <p>The {@code factory}-generated and {@code map} classes determine the * multimap iteration order. They also specify the behavior of the * {@code equals}, {@code hashCode}, and {@code toString} methods for the * multimap and its returned views. The multimap's {@code get}, {@code * removeAll}, and {@code replaceValues} methods return {@code RandomAccess} * lists if the factory does. However, the multimap's {@code get} method * returns instances of a different class than does {@code factory.get()}. * <p> * <p>The multimap is serializable if {@code map}, {@code factory}, the * lists generated by {@code factory}, and the multimap contents are all * serializable. * <p> * <p>The multimap is not threadsafe when any concurrent operations update the * multimap, even if {@code map} and the instances generated by * {@code factory} are. Concurrent read operations will work correctly. To * allow concurrent update operations, wrap the multimap with a call to * {@link #synchronizedListMultimap}. * <p> * <p>Call this method only when the simpler methods * {@link ArrayListMultimap#create()} and {@link LinkedListMultimap#create()} * won't suffice. * <p> * <p>Note: the multimap assumes complete ownership over of {@code map} and * the lists returned by {@code factory}. Those objects should not be manually * updated, they should be empty when provided, and they should not use soft, * weak, or phantom references. * * @param map place to store the mapping from each key to its corresponding * values * @param factory supplier of new, empty lists that will each hold all values * for a given key * @throws IllegalArgumentException if {@code map} is not empty */
public static <K, V> ListMultimap<K, V> newListMultimap( Map<K, Collection<V>> map, final Supplier<? extends List<V>> factory) { return new CustomListMultimap<K, V>(map, factory); } static boolean equalsImpl(Multimap<?, ?> multimap, Object object) { if (object == multimap) { return true; } if (object instanceof Multimap) { Multimap<?, ?> that = (Multimap<?, ?>) object; return multimap.asMap().equals(that.asMap()); } return false; } private static class CustomListMultimap<K, V> extends AbstractListMultimap<K, V> { private static final long serialVersionUID = 0; transient Supplier<? extends List<V>> factory; CustomListMultimap(Map<K, Collection<V>> map, Supplier<? extends List<V>> factory) { super(map); this.factory = checkNotNull(factory); } @Override protected List<V> createCollection() { return factory.get(); }
@serialDatathe factory and the backing map
/** * @serialData the factory and the backing map */
private void writeObject(ObjectOutputStream stream) throws IOException { stream.defaultWriteObject(); stream.writeObject(factory); stream.writeObject(backingMap()); } @SuppressWarnings("unchecked") // reading data stored by writeObject private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { stream.defaultReadObject(); factory = (Supplier<? extends List<V>>) stream.readObject(); Map<K, Collection<V>> map = (Map<K, Collection<V>>) stream.readObject(); setMap(map); } }
A skeleton implementation of Multimap.entries().
/** * A skeleton implementation of {@link Multimap#entries()}. */
abstract static class Entries<K, V> extends AbstractCollection<Entry<K, V>> { abstract Multimap<K, V> multimap(); @Override public int size() { return multimap().size(); } @Override public boolean contains(Object o) { if (o instanceof Map.Entry) { Entry<?, ?> entry = (Entry<?, ?>) o; return multimap().containsEntry(entry.getKey(), entry.getValue()); } return false; } @Override public boolean remove(Object o) { if (o instanceof Map.Entry) { Entry<?, ?> entry = (Entry<?, ?>) o; return multimap().remove(entry.getKey(), entry.getValue()); } return false; } @Override public void clear() { multimap().clear(); } } // TODO(jlevy): Create methods that filter a SortedSetMultimap. }