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 implements Map { private final Map map; private final DefaultProvider defaultProvider; private final boolean putDefault; public DefaultMapAdapter(Map map, DefaultProvider defaultProvider, boolean putDefault) { this.defaultProvider = defaultProvider; this.map = map; this.putDefault = putDefault; } public DefaultMapAdapter(Map map, final V defaultValue, boolean putDefault) { this(map, new DefaultProvider() { @Override public V get(Object key) { return defaultValue; } }, putDefault); } public DefaultMapAdapter(final V defaultValue, boolean putDefault) { this(new HashMap(), defaultValue, putDefault); } public DefaultMapAdapter(DefaultProvider defaultProvider, boolean putDefault) { this(new HashMap(), defaultProvider, putDefault); } public DefaultMapAdapter(Map map, final V defaultValue) { this(map, defaultValue, false); } public DefaultMapAdapter(Map map, DefaultProvider defaultProvider) { this(map, defaultProvider, false); } public DefaultMapAdapter(final V defaultValue) { this(defaultValue, false); } public DefaultMapAdapter(DefaultProvider 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> 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 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 m) { map.putAll(m); } @Override public V remove(Object key) { return map.remove(key); } @Override public int size() { return map.size(); } @Override public Collection values() { return map.values(); } }