package com.revolsys.collection.map; import java.io.Serializable; import java.util.AbstractMap; import java.util.AbstractSet; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import java.util.WeakHashMap; /** * <p>Wrapper around {@link Map} where the key is wrapped in an {@link ObjectKey} so that * == is used instead of equals for equality.</p> * * @param <K> * @param <V> */ public class ObjectKeyMap<K, V> implements Map<K, V> { public class Entry implements Map.Entry<K, V>, Serializable { private static final long serialVersionUID = -8499721149061103585L; private Map.Entry<ObjectKey, V> entry; private K key; private V value; public Entry(final K key, final V value) { this.key = key; this.value = value; } public Entry(final Map.Entry<ObjectKey, V> entry) { this.entry = entry; } @Override public boolean equals(final Object object) { if (object instanceof Map.Entry) { @SuppressWarnings("unchecked") final Map.Entry<K, V> entry = (Map.Entry<K, V>)object; if (getKey() == entry.getKey()) { final V value = getValue(); final V otherValue = entry.getValue(); if (value == null) { return otherValue == null; } else if (otherValue != null) { return value.equals(otherValue); } } } return false; } @SuppressWarnings("unchecked") @Override public K getKey() { if (this.entry == null) { return this.key; } else { return (K)this.entry.getKey().getValue(); } } @Override public V getValue() { if (this.entry == null) { return this.value; } else { return this.entry.getValue(); } } @Override public int hashCode() { return (this.key == null ? 0 : this.key.hashCode()) ^ (this.value == null ? 0 : this.value.hashCode()); } @Override public V setValue(final V value) { if (this.entry == null) { final V oldValue = this.value; this.value = value; return oldValue; } else { return this.entry.setValue(value); } } @Override public String toString() { return getKey() + "=" + getValue(); } } private class EntrySet extends AbstractSet<java.util.Map.Entry<K, V>> { private final ObjectKeyMap<K, V> map; public EntrySet(final ObjectKeyMap<K, V> map) { this.map = map; } @SuppressWarnings("unchecked") @Override public boolean contains(final Object object) { if (object instanceof Map.Entry) { final Map.Entry<K, V> entry = (Map.Entry<K, V>)object; final K key = entry.getKey(); if (key != null) { final ObjectKey objectKey = new ObjectKey(key); final V value = entry.getValue(); final Map.Entry<ObjectKey, V> objectKeyEntry = new AbstractMap.SimpleEntry<>(objectKey, value); return this.map.map.entrySet().contains(objectKeyEntry); } } return false; } @Override public Iterator<java.util.Map.Entry<K, V>> iterator() { return new EntrySetIterator(this.map.map.entrySet().iterator()); } @Override public int size() { return this.map.size(); } } private class EntrySetIterator implements Iterator<java.util.Map.Entry<K, V>> { private final Iterator<java.util.Map.Entry<ObjectKey, V>> iterator; public EntrySetIterator(final Iterator<java.util.Map.Entry<ObjectKey, V>> iterator) { this.iterator = iterator; } @Override public boolean hasNext() { return this.iterator.hasNext(); } @Override public Map.Entry<K, V> next() { final Map.Entry<ObjectKey, V> entry = this.iterator.next(); return new Entry(entry); } @Override public void remove() { this.iterator.remove(); } } private class KeySet extends AbstractSet<K> { private final ObjectKeyMap<K, V> map; public KeySet(final ObjectKeyMap<K, V> map) { this.map = map; } @Override public boolean contains(final Object paramObject) { return this.map.containsKey(paramObject); } @Override public Iterator<K> iterator() { return new KeySetIterator(this.map.map.keySet().iterator()); } @Override public int size() { return this.map.size(); } } private class KeySetIterator implements Iterator<K> { private final Iterator<ObjectKey> iterator; public KeySetIterator(final Iterator<ObjectKey> iterator) { this.iterator = iterator; } @Override public boolean hasNext() { return this.iterator.hasNext(); } @SuppressWarnings("unchecked") @Override public K next() { return (K)this.iterator.next().getValue(); } @Override public void remove() { this.iterator.remove(); } } public static <KEY, VAL> Map<KEY, VAL> hash() { final Map<ObjectKey, VAL> map = new HashMap<>(); return new ObjectKeyMap<>(map); } public static <KEY, VAL> Map<KEY, VAL> linkedHash() { final Map<ObjectKey, VAL> map = new LinkedHashMap<>(); return new ObjectKeyMap<>(map); } public static <KEY, VAL> Map<KEY, VAL> weak() { final Map<ObjectKey, VAL> map = new WeakHashMap<>(); return new ObjectKeyMap<>(map); } private EntrySet entrySet; private KeySet keySet; private Map<ObjectKey, V> map; public ObjectKeyMap() { this(new HashMap<ObjectKey, V>()); } public ObjectKeyMap(final Map<ObjectKey, V> map) { this.map = map; } @Override public void clear() { this.map.clear(); } @Override public boolean containsKey(final Object key) { if (key == null) { return false; } else { final ObjectKey objectKey = new ObjectKey(key); return this.map.containsKey(objectKey); } } @Override public boolean containsValue(final Object value) { return this.map.containsValue(value); } @Override public Set<java.util.Map.Entry<K, V>> entrySet() { if (this.entrySet == null) { this.entrySet = new EntrySet(this); } return this.entrySet; } @Override public V get(final Object key) { if (key == null) { return null; } else { final ObjectKey objectKey = new ObjectKey(key); return this.map.get(objectKey); } } @Override public int hashCode() { int i = 0; final Iterator<java.util.Map.Entry<K, V>> localIterator = entrySet().iterator(); while (localIterator.hasNext()) { i += localIterator.next().hashCode(); } return i; } @Override public boolean isEmpty() { return this.map.isEmpty(); } @Override public Set<K> keySet() { if (this.keySet == null) { this.keySet = new KeySet(this); } return this.keySet; } @Override public V put(final K key, final V value) { if (key == null) { throw new NullPointerException("Key cannot be null"); } else { final ObjectKey objectKey = new ObjectKey(key); if (value == null) { return this.map.remove(objectKey); } else { return this.map.put(objectKey, value); } } } @Override public void putAll(final Map<? extends K, ? extends V> map) { for (final Map.Entry<? extends K, ? extends V> entry : map.entrySet()) { final K key = entry.getKey(); final V value = entry.getValue(); put(key, value); } } @Override public V remove(final Object key) { if (key == null) { throw new NullPointerException("Key cannot be null"); } else { final ObjectKey objectKey = new ObjectKey(key); return this.map.remove(objectKey); } } @Override public int size() { return this.map.size(); } @Override public String toString() { final Iterator<Map.Entry<K, V>> localIterator = entrySet().iterator(); if (!localIterator.hasNext()) { return "{}"; } final StringBuilder localStringBuilder = new StringBuilder(); localStringBuilder.append('{'); while (true) { final Map.Entry<K, V> localEntry = localIterator.next(); final Object localObject1 = localEntry.getKey(); final Object localObject2 = localEntry.getValue(); localStringBuilder.append(localObject1 == this ? "(this Map)" : localObject1); localStringBuilder.append('='); localStringBuilder.append(localObject2 == this ? "(this Map)" : localObject2); if (!localIterator.hasNext()) { return "}"; } localStringBuilder.append(", "); } } @Override public Collection<V> values() { return this.map.values(); } }