package de.invesdwin.util.collections.loadingcache.guava.internal; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.annotation.concurrent.NotThreadSafe; import com.google.common.base.Optional; /** * This is a workaround to make googles ComputingMap work with null values. * * @see <a href="http://code.google.com/p/google-collections/issues/detail?id=166">Source</a> */ @SuppressWarnings("unchecked") @NotThreadSafe public class OptionalValueWrapperMap<K, V> implements Map<K, V> { private final Map<K, Optional<V>> delegate; public OptionalValueWrapperMap(final Map<K, Optional<V>> delegate) { this.delegate = delegate; } @Override public int size() { return delegate.size(); } @Override public boolean isEmpty() { return delegate.isEmpty(); } /** * If key == null this method returns false. This is because googles ComputingMaps do not allow null keys. */ @Override public boolean containsKey(final Object key) { if (key == null) { return false; } else { return delegate.containsKey(key); } } /** * If key == null this method returns false. This is because googles ComputingMaps do not allow null value normally. */ @Override public boolean containsValue(final Object value) { if (value == null) { return false; } else { try { return delegate.containsValue(Optional.fromNullable((V) value)); } catch (final ClassCastException e) { return false; } } } @Override public V get(final Object key) { final Optional<V> value = delegate.get(key); return maybeGet((K) key, value); } @Override public V put(final K key, final V value) { if (isPutAllowed(key, value)) { final Optional<V> previousValue = delegate.put(key, Optional.fromNullable(value)); return maybeGet(key, previousValue); } else { throw new IllegalArgumentException("isCacheAllowed(value) returned false, check this before using put!"); } } @Override public V remove(final Object key) { final Optional<V> value = delegate.remove(key); return maybeGet((K) key, value); } @Override public void putAll(final Map<? extends K, ? extends V> m) { for (final Entry<? extends K, ? extends V> e : m.entrySet()) { put(e.getKey(), e.getValue()); } } @Override public void clear() { delegate.clear(); } @Override public Set<K> keySet() { return delegate.keySet(); } @Override public Collection<V> values() { final Set<V> values = new HashSet<V>(); final Collection<Optional<V>> maybeNullValues = delegate.values(); for (final Optional<V> maybeNullValue : maybeNullValues) { final V value = maybeGet((K) null, maybeNullValue); if (value != null) { values.add(value); } } return values; } @Override public Set<Entry<K, V>> entrySet() { final Map<K, V> map = new HashMap<K, V>(); for (final Entry<K, Optional<V>> e : delegate.entrySet()) { final V value = maybeGet(e.getKey(), e.getValue()); map.put(e.getKey(), value); } return map.entrySet(); } protected final V maybeGet(final K key, final Optional<V> value) { if (value != null) { final V v = value.orNull(); if (key != null && !isPutAllowed(key, v)) { remove(key); } return v; } else { return (V) null; } } public boolean isPutAllowed(final K key, final V value) { return true; } }