/** * Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.util; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; /** * Maps {@link Class} objects to values. A value may be retrieved by either the {@link Class} with which it was * associated, or a {@link Class} corresponding to a subclass or implementation of this. If there are potentially * multiple matches for a given {@link Class} then the 'closest' matching association is returned, starting with the * class hierarchy and then any interfaces. * <p> * Results, both positive and negative, are cached to improve future lookup performance. * * @param <T> the type of the values */ public class ClassMap<T> implements Map<Class<?>, T> { private final Map<Class<?>, T> _map = new HashMap<>(); private final Map<Class<?>, T> _cache = new HashMap<>(); private boolean _cacheModified; @Override public synchronized void clear() { _map.clear(); _cache.clear(); } @Override public synchronized boolean containsKey(Object key) { return get(key) != null; } @Override public synchronized boolean containsValue(Object value) { return _map.containsValue(value); } @Override public synchronized Set<java.util.Map.Entry<Class<?>, T>> entrySet() { // Unmodifiable breaks the interface return Collections.unmodifiableSet(_map.entrySet()); } @Override public synchronized T get(Object key) { Class<?> clazz = (Class<?>) key; if (_cache.containsKey(clazz)) { // Could be null return _cache.get(key); } if (clazz.getSuperclass() != null) { T value = get(clazz.getSuperclass()); if (value != null) { addValueToCache(clazz, value); return value; } } for (Class<?> intface : clazz.getInterfaces()) { T value = get(intface); if (value != null) { addValueToCache(clazz, value); return value; } } addValueToCache(clazz, null); return null; } @Override public synchronized boolean isEmpty() { return _map.isEmpty(); } @Override public synchronized Set<Class<?>> keySet() { // Unmodifiable breaks the interface return Collections.unmodifiableSet(_map.keySet()); } @Override public synchronized T put(Class<?> key, T value) { T result = _map.put(key, value); if (_cacheModified) { initCache(); } else { _cache.put(key, value); } return result; } @Override public synchronized void putAll(Map<? extends Class<?>, ? extends T> m) { _map.putAll(m); if (_cacheModified) { initCache(); } else { _cache.putAll(m); } } @Override public synchronized T remove(Object key) { T result = _map.remove(key); if (_cacheModified) { initCache(); } else { _cache.remove(key); } return result; } @Override public synchronized int size() { return _map.size(); } @Override public synchronized Collection<T> values() { // Unmodifiable breaks the interface return Collections.unmodifiableCollection(_map.values()); } //------------------------------------------------------------------------- private void addValueToCache(Class<?> key, T value) { _cache.put(key, value); _cacheModified = true; } private void initCache() { _cache.clear(); _cache.putAll(_map); _cacheModified = false; } }