/*
* 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: - IllegalArgumentException – if
map
is not empty
/**
* 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();
}
@serialData the 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.
}