package tc.oc.commons.core.util; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; /** * Adapt a Map to return a default value for missing keys. * The default value can be constant or generated dynamically * by a DefaultProvider. Only the get() method uses default * values. All other methods behave normally for missing keys. */ public class DefaultMapAdapter<K, V> implements Map<K, V> { private final Map<K, V> map; private final DefaultProvider<? super K, ? extends V> defaultProvider; private final boolean putDefault; public DefaultMapAdapter(Map<K, V> map, DefaultProvider<? super K, ? extends V> defaultProvider, boolean putDefault) { this.defaultProvider = defaultProvider; this.map = map; this.putDefault = putDefault; } public DefaultMapAdapter(Map<K, V> map, final V defaultValue, boolean putDefault) { this(map, new DefaultProvider<K, V>() { @Override public V get(Object key) { return defaultValue; } }, putDefault); } public DefaultMapAdapter(final V defaultValue, boolean putDefault) { this(new HashMap<K, V>(), defaultValue, putDefault); } public DefaultMapAdapter(DefaultProvider<? super K, ? extends V> defaultProvider, boolean putDefault) { this(new HashMap<K, V>(), defaultProvider, putDefault); } public DefaultMapAdapter(Map<K, V> map, final V defaultValue) { this(map, defaultValue, false); } public DefaultMapAdapter(Map<K, V> map, DefaultProvider<? super K, ? extends V> defaultProvider) { this(map, defaultProvider, false); } public DefaultMapAdapter(final V defaultValue) { this(defaultValue, false); } public DefaultMapAdapter(DefaultProvider<? super K, ? extends V> defaultProvider) { this(defaultProvider, false); } @Override public V get(Object key) { V value = this.map.get(key); if(value == null) { value = this.defaultProvider.get((K) key); if(this.putDefault) this.map.put((K) key, value); } return value; } public V getOrDefault(K key) { V value = this.map.get(key); if(value == null) { value = this.defaultProvider.get(key); } return value; } public V getOrCreate(K key) { V value = this.map.get(key); if(value == null) { value = this.defaultProvider.get(key); this.map.put(key, value); } return value; } public V getOrNull(K key) { return this.map.get(key); } @Override public void clear() { map.clear(); } @Override public boolean containsKey(Object key) { return map.containsKey(key); } @Override public boolean containsValue(Object value) { return map.containsValue(value); } @Override public Set<Entry<K,V>> entrySet() { return map.entrySet(); } @Override public boolean equals(Object o) { return map.equals(o); } @Override public int hashCode() { return map.hashCode(); } @Override public boolean isEmpty() { return map.isEmpty(); } @Override public Set<K> keySet() { return map.keySet(); } /** * If the given key was not previously in the map, the default value is returned, rather than null. * This is so that put(x, ...) always returns the same thing as get(x) for any given state. * * {@link #putNoDefault} can be used if you want null returned for new keys, instead of the default. */ public V put(K key, V value) { V previous = map.put(key, value); return previous != null ? previous : this.defaultProvider.get(key); } public V putNoDefault(K key, V value) { return map.put(key, value); } public void putAll(Map<? extends K, ? extends V> m) { map.putAll(m); } @Override public V remove(Object key) { return map.remove(key); } @Override public int size() { return map.size(); } @Override public Collection<V> values() { return map.values(); } }