236 lines
6.4 KiB
Java
236 lines
6.4 KiB
Java
package com.comphenix.protocol.wrappers.collection;
|
|
|
|
import java.util.Collection;
|
|
import java.util.Iterator;
|
|
import java.util.Map;
|
|
import java.util.Map.Entry;
|
|
import java.util.Set;
|
|
|
|
import javax.annotation.Nullable;
|
|
|
|
import com.google.common.base.Joiner;
|
|
import com.google.common.base.Preconditions;
|
|
import com.google.common.collect.Iterables;
|
|
import com.google.common.collect.Multimap;
|
|
import com.google.common.collect.Multiset;
|
|
|
|
/**
|
|
* Represents a multimap that wraps another multimap by transforming the entries that are going in and out.
|
|
* @author Kristian
|
|
*
|
|
* @param <Key> - the key.
|
|
* @param <VInner> - the inner value type.
|
|
* @param <VOuter> - the outer value type.
|
|
*/
|
|
public abstract class ConvertedMultimap<Key, VInner, VOuter> extends AbstractConverted<VInner, VOuter> implements Multimap<Key, VOuter> {
|
|
// Inner multimap
|
|
private Multimap<Key, VInner> inner;
|
|
|
|
public ConvertedMultimap(Multimap<Key, VInner> inner) {
|
|
this.inner = Preconditions.checkNotNull(inner, "inner map cannot be NULL.");
|
|
}
|
|
|
|
/**
|
|
* Wrap a given collection.
|
|
* @param inner - the inner collection.
|
|
* @return The outer collection.
|
|
*/
|
|
protected Collection<VOuter> toOuterCollection(Collection<VInner> inner) {
|
|
return new ConvertedCollection<VInner, VOuter>(inner) {
|
|
@Override
|
|
protected VInner toInner(VOuter outer) {
|
|
return ConvertedMultimap.this.toInner(outer);
|
|
}
|
|
|
|
@Override
|
|
protected VOuter toOuter(VInner inner) {
|
|
return ConvertedMultimap.this.toOuter(inner);
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return "[" + Joiner.on(", ").join(this) + "]";
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Wrap a given collection.
|
|
* @param outer - the outer collection.
|
|
* @return The inner collection.
|
|
*/
|
|
protected Collection<VInner> toInnerCollection(Collection<VOuter> outer) {
|
|
return new ConvertedCollection<VOuter, VInner>(outer) {
|
|
@Override
|
|
protected VOuter toInner(VInner outer) {
|
|
return ConvertedMultimap.this.toOuter(outer);
|
|
}
|
|
|
|
@Override
|
|
protected VInner toOuter(VOuter inner) {
|
|
return ConvertedMultimap.this.toInner(inner);
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return "[" + Joiner.on(", ").join(this) + "]";
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Convert to an inner object if its of the correct type, otherwise leave it.
|
|
* @param outer - the outer object.
|
|
* @return The inner object, or the same object.
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
protected Object toInnerObject(Object outer) {
|
|
return toInner((VOuter) outer);
|
|
}
|
|
|
|
@Override
|
|
public int size() {
|
|
return inner.size();
|
|
}
|
|
|
|
@Override
|
|
public boolean isEmpty() {
|
|
return inner.isEmpty();
|
|
}
|
|
|
|
@Override
|
|
public boolean containsKey(@Nullable Object key) {
|
|
return inner.containsKey(key);
|
|
}
|
|
|
|
@Override
|
|
public boolean containsValue(@Nullable Object value) {
|
|
return inner.containsValue(toInnerObject(value));
|
|
}
|
|
|
|
@Override
|
|
public boolean containsEntry(@Nullable Object key, @Nullable Object value) {
|
|
return inner.containsEntry(key, toInnerObject(value));
|
|
}
|
|
|
|
@Override
|
|
public boolean put(@Nullable Key key, @Nullable VOuter value) {
|
|
return inner.put(key, toInner(value));
|
|
}
|
|
|
|
@Override
|
|
public boolean remove(@Nullable Object key, @Nullable Object value) {
|
|
return inner.remove(key, toInnerObject(value));
|
|
}
|
|
|
|
@Override
|
|
public boolean putAll(@Nullable Key key, Iterable<? extends VOuter> values) {
|
|
return inner.putAll(key, Iterables.transform(values, getInnerConverter()));
|
|
}
|
|
|
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
|
@Override
|
|
public boolean putAll(Multimap<? extends Key, ? extends VOuter> multimap) {
|
|
return inner.putAll(new ConvertedMultimap<Key, VOuter, VInner>((Multimap) multimap) {
|
|
@Override
|
|
protected VOuter toInner(VInner outer) {
|
|
return ConvertedMultimap.this.toOuter(outer);
|
|
}
|
|
|
|
@Override
|
|
protected VInner toOuter(VOuter inner) {
|
|
return ConvertedMultimap.this.toInner(inner);
|
|
}
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public Collection<VOuter> replaceValues(@Nullable Key key, Iterable<? extends VOuter> values) {
|
|
return toOuterCollection(
|
|
inner.replaceValues(key, Iterables.transform(values, getInnerConverter()))
|
|
);
|
|
}
|
|
|
|
@Override
|
|
public Collection<VOuter> removeAll(@Nullable Object key) {
|
|
return toOuterCollection(inner.removeAll(key));
|
|
}
|
|
|
|
@Override
|
|
public void clear() {
|
|
inner.clear();
|
|
}
|
|
|
|
@Override
|
|
public Collection<VOuter> get(@Nullable Key key) {
|
|
return toOuterCollection(inner.get(key));
|
|
}
|
|
|
|
@Override
|
|
public Set<Key> keySet() {
|
|
return inner.keySet();
|
|
}
|
|
|
|
@Override
|
|
public Multiset<Key> keys() {
|
|
return inner.keys();
|
|
}
|
|
|
|
@Override
|
|
public Collection<VOuter> values() {
|
|
return toOuterCollection(inner.values());
|
|
}
|
|
|
|
@Override
|
|
public Collection<Entry<Key, VOuter>> entries() {
|
|
return ConvertedMap.convertedEntrySet(inner.entries(), (key, outer) -> toInner(outer), (key, inner) -> toOuter(inner));
|
|
}
|
|
|
|
@Override
|
|
public Map<Key, Collection<VOuter>> asMap() {
|
|
return new ConvertedMap<Key, Collection<VInner>, Collection<VOuter>>(inner.asMap()) {
|
|
@Override
|
|
protected Collection<VInner> toInner(Collection<VOuter> outer) {
|
|
return toInnerCollection(outer);
|
|
}
|
|
|
|
@Override
|
|
protected Collection<VOuter> toOuter(Collection<VInner> inner) {
|
|
return toOuterCollection(inner);
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Returns a string representation of this map. The string representation
|
|
* consists of a list of key-value mappings in the order returned by the
|
|
* map's <code>entrySet</code> view's iterator, enclosed in braces
|
|
* (<code>"{}"</code>). Adjacent mappings are separated by the characters
|
|
* <code>", "</code> (comma and space). Each key-value mapping is rendered as
|
|
* the key followed by an equals sign (<code>"="</code>) followed by the
|
|
* associated value. Keys and values are converted to strings as by
|
|
* {@link String#valueOf(Object)}.
|
|
*
|
|
* @return a string representation of this map
|
|
*/
|
|
public String toString() {
|
|
Iterator<Entry<Key, VOuter>> i = entries().iterator();
|
|
if (!i.hasNext())
|
|
return "{}";
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
sb.append('{');
|
|
for (;;) {
|
|
Entry<Key, VOuter> e = i.next();
|
|
Key key = e.getKey();
|
|
VOuter value = e.getValue();
|
|
sb.append(key == this ? "(this Map)" : key);
|
|
sb.append('=');
|
|
sb.append(value == this ? "(this Map)" : value);
|
|
if (! i.hasNext())
|
|
return sb.append('}').toString();
|
|
sb.append(", ");
|
|
}
|
|
}
|
|
}
|