/* * Copyright 2013 the original author or 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 ratpack.util.internal; import com.google.common.base.MoreObjects; import com.google.common.collect.*; import ratpack.util.MultiValueMap; import ratpack.util.Types; import java.util.*; import java.util.stream.Collectors; public class ImmutableDelegatingMultiValueMap<K, V> implements MultiValueMap<K, V> { private static final ImmutableDelegatingMultiValueMap<Object, Object> EMPTY = new ImmutableDelegatingMultiValueMap<>(ImmutableMap.of()); @SuppressWarnings("unchecked") public static <K, V> MultiValueMap<K, V> empty() { return Types.cast(EMPTY); } private final Map<K, List<V>> delegate; public ImmutableDelegatingMultiValueMap(Map<K, List<V>> map) { this.delegate = map; } @SuppressWarnings("unchecked") public List<V> getAll(K key) { return MoreObjects.firstNonNull(delegate.get(key), Collections.<V>emptyList()); } @SuppressWarnings("unchecked") public Map<K, List<V>> getAll() { return delegate; } public int size() { return delegate.size(); } public boolean isEmpty() { return delegate.isEmpty(); } public boolean containsKey(Object key) { return delegate.containsKey(key); } public boolean containsValue(Object value) { for (List<? extends V> values : delegate.values()) { //noinspection SuspiciousMethodCalls if (values.contains(value)) { return true; } } return false; } public V get(Object key) { List<? extends V> result = delegate.get(key); return result != null && result.size() > 0 ? result.get(0) : null; } public V put(K key, V value) { throw new UnsupportedOperationException("This implementation is immutable"); } public V remove(Object key) { throw new UnsupportedOperationException("This implementation is immutable"); } @SuppressWarnings("NullableProblems") public void putAll(Map<? extends K, ? extends V> m) { throw new UnsupportedOperationException("This implementation is immutable"); } public void clear() { throw new UnsupportedOperationException("This implementation is immutable"); } @Override public ListMultimap<K, V> asMultimap() { ImmutableListMultimap.Builder<K, V> builder = ImmutableListMultimap.builder(); for (Entry<? extends K, ? extends List<? extends V>> entry : delegate.entrySet()) { builder.putAll(entry.getKey(), entry.getValue()); } return builder.build(); } @SuppressWarnings({"unchecked", "NullableProblems"}) public Set<K> keySet() { return delegate.keySet(); } @SuppressWarnings("NullableProblems") public Collection<V> values() { return Lists.newArrayList(Iterables.concat(delegate.values())); } @SuppressWarnings("NullableProblems") public Set<Entry<K, V>> entrySet() { return delegate.entrySet().stream() .filter(entry -> entry.getValue().size() > 0) .map(entry -> new AbstractMap.SimpleImmutableEntry<>(entry.getKey(), entry.getValue().get(0))) .collect(Collectors.toSet()); } @Override public String toString() { if (delegate.isEmpty()) { return "[:]"; } StringBuilder buffer = new StringBuilder("["); boolean first = true; for (Entry<? extends K, ? extends List<? extends V>> entry : delegate.entrySet()) { if (first) { first = false; } else { buffer.append(", "); } buffer.append(entry.getKey().toString()); buffer.append(":["); boolean firstValue = true; for (V value : entry.getValue()) { if (firstValue) { firstValue = false; } else { buffer.append(", "); } buffer.append(value.toString()); } buffer.append("]"); } buffer.append("]"); return buffer.toString(); } }