001 /*--------------------------------------------------------------------------+ 002 $Id: ClassHierarchyMap.java 26283 2010-02-18 11:18:57Z juergens $ 003 | | 004 | Copyright 2005-2010 Technische Universitaet Muenchen | 005 | | 006 | Licensed under the Apache License, Version 2.0 (the "License"); | 007 | you may not use this file except in compliance with the License. | 008 | You may obtain a copy of the License at | 009 | | 010 | http://www.apache.org/licenses/LICENSE-2.0 | 011 | | 012 | Unless required by applicable law or agreed to in writing, software | 013 | distributed under the License is distributed on an "AS IS" BASIS, | 014 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 015 | See the License for the specific language governing permissions and | 016 | limitations under the License. | 017 +--------------------------------------------------------------------------*/ 018 package edu.tum.cs.commons.collections; 019 020 import java.util.ArrayList; 021 import java.util.Collection; 022 import java.util.HashMap; 023 import java.util.List; 024 import java.util.Set; 025 026 import edu.tum.cs.commons.reflect.ReflectionUtils; 027 028 /** 029 * This class provides a mapping from classes to values. The speciality of this 030 * class lies in its awareness of the class hierarchy: If no value was found 031 * this class tries to retrieve values stored for the super classes of the 032 * provided class. If values are stored for multiple super classes of the class 033 * the one value that maps to the super class closest to the provided class will 034 * be returned. 035 * <p> 036 * 037 * @param <T> 038 * This type parameter allows to specify a lower bound of the classes 039 * used as keys. If this is unnecessary, use {@link Object}. 040 * @author Florian Deissenboeck 041 * @author $Author: juergens $ 042 * @version $Rev: 26283 $ 043 * @levd.rating GREEN Hash: C47D9975C69CF7FBCB80888A00CE1A9F 044 */ 045 public class ClassHierarchyMap<T, V> { 046 /** Underlying map. */ 047 private final HashMap<Class<? extends T>, V> map = new HashMap<Class<? extends T>, V>(); 048 049 /** @see java.util.Map#clear() */ 050 public void clear() { 051 map.clear(); 052 } 053 054 /** 055 * Get value stored for a class. If no value was found this method tries to 056 * retrieve values stored for the super classes of the provided class. If 057 * values are stored for multiple super classes of the class the one value 058 * that maps to the super class closest to the provided class will be 059 * returned. 060 * <p> 061 * If a key is stored for the provided class the performance of this method 062 * equals the performance of {@link HashMap#get(Object)}. Otherwise its 063 * worst case performance is O(DIT(key)). 064 * 065 * @param key 066 * the key 067 * @return the value stored for the provided key or one if its super classes 068 * or <code>null</code> if no value was found. 069 */ 070 public V get(Class<?> key) { 071 V value = map.get(key); 072 if (value != null) { 073 return value; 074 } 075 076 List<Class<?>> superClasses = ReflectionUtils.getSuperClasses(key); 077 078 for (Class<?> clazz : superClasses) { 079 value = map.get(clazz); 080 if (value != null) { 081 return value; 082 } 083 } 084 return null; 085 } 086 087 /** 088 * Get value stored for the declaring class of the provided element. 089 * 090 * @see #get(Class) 091 */ 092 public V get(T element) { 093 return get(element.getClass()); 094 } 095 096 /** 097 * Retrieve a list of values stored for the provided class and its super 098 * classes. List starts with the value stored for the provided class (if 099 * present). 100 * 101 * @return the list of values or an empty list of no value was found. 102 */ 103 public List<V> getAll(Class<?> key) { 104 ArrayList<V> list = new ArrayList<V>(); 105 106 List<Class<?>> classes = ReflectionUtils.getSuperClasses(key); 107 108 classes.add(0, key); 109 110 for (Class<?> clazz : classes) { 111 V value = map.get(clazz); 112 113 if (value != null) { 114 list.add(value); 115 } 116 } 117 118 return list; 119 } 120 121 /** 122 * Get value list for the declaring class of the provided element. 123 * 124 * @see #getAll(Class) 125 */ 126 public List<V> getAll(T element) { 127 return getAll(element.getClass()); 128 } 129 130 /** 131 * Get value stored for this class. Unlike {@link #get(Class)} this does not 132 * retrieve values stored for super classes. 133 */ 134 public V getDeclared(Class<?> key) { 135 return map.get(key); 136 } 137 138 /** 139 * Get value stored for the declaring class of the provided element. Unlike 140 * {@link #get(Object)} this does not retrieve values stored for super 141 * classes. 142 */ 143 public V getDeclared(T element) { 144 return getDeclared(element.getClass()); 145 } 146 147 /** 148 * @see java.util.Map#isEmpty() 149 */ 150 public boolean isEmpty() { 151 return map.isEmpty(); 152 } 153 154 /** 155 * @see java.util.Map#keySet() 156 */ 157 public Set<Class<? extends T>> keySet() { 158 return map.keySet(); 159 } 160 161 /** 162 * Store a key-value-pair. 163 * 164 * @see java.util.Map#put(Object, Object) 165 */ 166 public V put(Class<? extends T> key, V value) { 167 return map.put(key, value); 168 } 169 170 /** 171 * @see java.util.Map#remove(Object) 172 */ 173 public V remove(Class<?> key) { 174 return map.remove(key); 175 } 176 177 /** 178 * @see java.util.Map#size() 179 */ 180 public int size() { 181 return map.size(); 182 } 183 184 /** 185 * @see java.util.Map#values() 186 */ 187 public Collection<V> values() { 188 return map.values(); 189 } 190 }