// Copyright (c) 1998-2008 Adrian Kuhn <akuhn(a)students.unibe.ch> // // This file is part of ch.akuhn.util. // // ch.akuhn.util is free software: you can redistribute it and/or modify it // under the terms of the GNU Lesser General Public License as published by the // Free Software Foundation, either version 3 of the License, or (at your // option) any later version. // // ch.akuhn.util is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public // License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with ch.akuhn.util. If not, see <http://www.gnu.org/licenses/>. // package ch.akuhn.util; import java.lang.reflect.Constructor; import java.util.HashMap; /** * A map that knows how to initialize missing mapping. * */ public abstract class CacheMap<K,V> extends HashMap<K,V> { @SuppressWarnings("unchecked") private static <A,T> T createInstanceOf(Class<T> instanceClass, A argument) { try { Constructor<T>[] inits = (Constructor<T>[]) instanceClass.getDeclaredConstructors(); for (Constructor<T> each : inits) { Class<?>[] params = each.getParameterTypes(); if (params.length == 1 && params[0].isAssignableFrom(argument.getClass())) { each.setAccessible(true); return each.newInstance(argument); } } return instanceClass.newInstance(); } catch (Exception ex) { throw new RuntimeException(ex); } } public static <A,T> CacheMap<A,T> instances(final Class<? extends T> instanceClass) { return new CacheMap<A,T>() { @Override public T initialize(A key) { return createInstanceOf(instanceClass, key); } }; } public CacheMap() { super(); } public CacheMap(HashMap<? extends K,? extends V> m) { super(m); } public CacheMap(int initialCapacity) { super(initialCapacity); } public CacheMap(int initialCapacity, float loadFactor) { super(initialCapacity, loadFactor); } @SuppressWarnings("unchecked") @Override public V get(Object key) { V value = super.get(key); if (value == null) { K k = (K) key; super.put(k, value = initialize(k)); } return value; } public abstract V initialize(K key); }