1674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen/* 2674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Copyright 2003,2004 The Apache Software Foundation 3674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * 4674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Licensed under the Apache License, Version 2.0 (the "License"); 5674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * you may not use this file except in compliance with the License. 6674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * You may obtain a copy of the License at 7674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * 8674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * http://www.apache.org/licenses/LICENSE-2.0 9674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * 10674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Unless required by applicable law or agreed to in writing, software 11674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * distributed under the License is distributed on an "AS IS" BASIS, 12674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * See the License for the specific language governing permissions and 14674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * limitations under the License. 15674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */ 16674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenpackage org.mockito.cglib.beans; 17674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 18674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport java.beans.*; 19674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport java.lang.reflect.Constructor; 20674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport java.lang.reflect.Method; 21674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport java.util.*; 22674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 23674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.asm.ClassVisitor; 24674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenimport org.mockito.cglib.core.*; 25674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 26674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen/** 27674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * A <code>Map</code>-based view of a JavaBean. The default set of keys is the 28674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * union of all property names (getters or setters). An attempt to set 29674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * a read-only property will be ignored, and write-only properties will 30674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * be returned as <code>null</code>. Removal of objects is not a 31674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * supported (the key set is fixed). 32674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @author Chris Nokleberg 33674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */ 34674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogenabstract public class BeanMap implements Map { 35674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen /** 36674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Limit the properties reflected in the key set of the map 37674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * to readable properties. 38674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @see BeanMap.Generator#setRequire 39674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */ 40674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public static final int REQUIRE_GETTER = 1; 41674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 42674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen /** 43674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Limit the properties reflected in the key set of the map 44674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * to writable properties. 45674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @see BeanMap.Generator#setRequire 46674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */ 47674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public static final int REQUIRE_SETTER = 2; 48674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 49674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen /** 50674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Helper method to create a new <code>BeanMap</code>. For finer 51674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * control over the generated instance, use a new instance of 52674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * <code>BeanMap.Generator</code> instead of this static method. 53674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @param bean the JavaBean underlying the map 54674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @return a new <code>BeanMap</code> instance 55674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */ 56674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public static BeanMap create(Object bean) { 57674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen Generator gen = new Generator(); 58674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen gen.setBean(bean); 59674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return gen.create(); 60674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 61674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 62674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public static class Generator extends AbstractClassGenerator { 63674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private static final Source SOURCE = new Source(BeanMap.class.getName()); 64674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 65674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private static final BeanMapKey KEY_FACTORY = 66674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen (BeanMapKey)KeyFactory.create(BeanMapKey.class, KeyFactory.CLASS_BY_NAME); 67674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 68674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen interface BeanMapKey { 69674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public Object newInstance(Class type, int require); 70674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 71674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 72674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private Object bean; 73674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private Class beanClass; 74674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen private int require; 75674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 76674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public Generator() { 77674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen super(SOURCE); 78674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 79674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 80674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen /** 81674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Set the bean that the generated map should reflect. The bean may be swapped 82674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * out for another bean of the same type using {@link #setBean}. 83674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Calling this method overrides any value previously set using {@link #setBeanClass}. 84674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * You must call either this method or {@link #setBeanClass} before {@link #create}. 85674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @param bean the initial bean 86674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */ 87674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public void setBean(Object bean) { 88674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen this.bean = bean; 89674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen if (bean != null) 90674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen beanClass = bean.getClass(); 91674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 92674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 93674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen /** 94674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Set the class of the bean that the generated map should support. 95674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * You must call either this method or {@link #setBeanClass} before {@link #create}. 96674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @param beanClass the class of the bean 97674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */ 98674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public void setBeanClass(Class beanClass) { 99674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen this.beanClass = beanClass; 100674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 101674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 102674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen /** 103674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Limit the properties reflected by the generated map. 104674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @param require any combination of {@link #REQUIRE_GETTER} and 105674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * {@link #REQUIRE_SETTER}; default is zero (any property allowed) 106674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */ 107674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public void setRequire(int require) { 108674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen this.require = require; 109674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 110674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 111674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen protected ClassLoader getDefaultClassLoader() { 112674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return beanClass.getClassLoader(); 113674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 114674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 115674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen /** 116674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Create a new instance of the <code>BeanMap</code>. An existing 117674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * generated class will be reused if possible. 118674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */ 119674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public BeanMap create() { 120674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen if (beanClass == null) 121674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen throw new IllegalArgumentException("Class of bean unknown"); 122674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen setNamePrefix(beanClass.getName()); 123674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return (BeanMap)super.create(KEY_FACTORY.newInstance(beanClass, require)); 124674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 125674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 126674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public void generateClass(ClassVisitor v) throws Exception { 127674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen new BeanMapEmitter(v, getClassName(), beanClass, require); 128674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 129674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 130674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen protected Object firstInstance(Class type) { 131674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return ((BeanMap)ReflectUtils.newInstance(type)).newInstance(bean); 132674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 133674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 134674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen protected Object nextInstance(Object instance) { 135674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return ((BeanMap)instance).newInstance(bean); 136674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 137674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 138674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 139674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen /** 140674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Create a new <code>BeanMap</code> instance using the specified bean. 141674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * This is faster than using the {@link #create} static method. 142674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @param bean the JavaBean underlying the map 143674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @return a new <code>BeanMap</code> instance 144674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */ 145674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen abstract public BeanMap newInstance(Object bean); 146674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 147674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen /** 148674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Get the type of a property. 149674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @param name the name of the JavaBean property 150674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @return the type of the property, or null if the property does not exist 151674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */ 152674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen abstract public Class getPropertyType(String name); 153674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 154674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen protected Object bean; 155674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 156674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen protected BeanMap() { 157674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 158674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 159674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen protected BeanMap(Object bean) { 160674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen setBean(bean); 161674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 162674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 163674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public Object get(Object key) { 164674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return get(bean, key); 165674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 166674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 167674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public Object put(Object key, Object value) { 168674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return put(bean, key, value); 169674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 170674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 171674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen /** 172674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Get the property of a bean. This allows a <code>BeanMap</code> 173674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * to be used statically for multiple beans--the bean instance tied to the 174674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * map is ignored and the bean passed to this method is used instead. 175674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @param bean the bean to query; must be compatible with the type of 176674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * this <code>BeanMap</code> 177674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @param key must be a String 178674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @return the current value, or null if there is no matching property 179674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */ 180674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen abstract public Object get(Object bean, Object key); 181674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 182674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen /** 183674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Set the property of a bean. This allows a <code>BeanMap</code> 184674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * to be used statically for multiple beans--the bean instance tied to the 185674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * map is ignored and the bean passed to this method is used instead. 186674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @param key must be a String 187674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @return the old value, if there was one, or null 188674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */ 189674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen abstract public Object put(Object bean, Object key, Object value); 190674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 191674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen /** 192674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Change the underlying bean this map should use. 193674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @param bean the new JavaBean 194674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @see #getBean 195674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */ 196674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public void setBean(Object bean) { 197674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen this.bean = bean; 198674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 199674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 200674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen /** 201674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * Return the bean currently in use by this map. 202674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @return the current JavaBean 203674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @see #setBean 204674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */ 205674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public Object getBean() { 206674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return bean; 207674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 208674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 209674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public void clear() { 210674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen throw new UnsupportedOperationException(); 211674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 212674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 213674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public boolean containsKey(Object key) { 214674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return keySet().contains(key); 215674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 216674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 217674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public boolean containsValue(Object value) { 218674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen for (Iterator it = keySet().iterator(); it.hasNext();) { 219674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen Object v = get(it.next()); 220674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen if (((value == null) && (v == null)) || value.equals(v)) 221674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return true; 222674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 223674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return false; 224674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 225674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 226674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public int size() { 227674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return keySet().size(); 228674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 229674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 230674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public boolean isEmpty() { 231674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return size() == 0; 232674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 233674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 234674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public Object remove(Object key) { 235674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen throw new UnsupportedOperationException(); 236674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 237674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 238674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public void putAll(Map t) { 239674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen for (Iterator it = t.keySet().iterator(); it.hasNext();) { 240674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen Object key = it.next(); 241674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen put(key, t.get(key)); 242674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 243674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 244674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 245674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public boolean equals(Object o) { 246674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen if (o == null || !(o instanceof Map)) { 247674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return false; 248674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 249674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen Map other = (Map)o; 250674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen if (size() != other.size()) { 251674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return false; 252674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 253674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen for (Iterator it = keySet().iterator(); it.hasNext();) { 254674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen Object key = it.next(); 255674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen if (!other.containsKey(key)) { 256674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return false; 257674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 258674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen Object v1 = get(key); 259674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen Object v2 = other.get(key); 260674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen if (!((v1 == null) ? v2 == null : v1.equals(v2))) { 261674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return false; 262674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 263674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 264674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return true; 265674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 266674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 267674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public int hashCode() { 268674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen int code = 0; 269674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen for (Iterator it = keySet().iterator(); it.hasNext();) { 270674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen Object key = it.next(); 271674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen Object value = get(key); 272674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen code += ((key == null) ? 0 : key.hashCode()) ^ 273674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen ((value == null) ? 0 : value.hashCode()); 274674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 275674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return code; 276674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 277674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 278674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen // TODO: optimize 279674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public Set entrySet() { 280674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen HashMap copy = new HashMap(); 281674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen for (Iterator it = keySet().iterator(); it.hasNext();) { 282674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen Object key = it.next(); 283674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen copy.put(key, get(key)); 284674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 285674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return Collections.unmodifiableMap(copy).entrySet(); 286674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 287674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 288674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public Collection values() { 289674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen Set keys = keySet(); 290674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen List values = new ArrayList(keys.size()); 291674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen for (Iterator it = keys.iterator(); it.hasNext();) { 292674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen values.add(get(it.next())); 293674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 294674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return Collections.unmodifiableCollection(values); 295674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 296674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen 297674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen /* 298674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen * @see java.util.AbstractMap#toString 299674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen */ 300674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen public String toString() 301674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen { 302674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen StringBuffer sb = new StringBuffer(); 303674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen sb.append('{'); 304674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen for (Iterator it = keySet().iterator(); it.hasNext();) { 305674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen Object key = it.next(); 306674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen sb.append(key); 307674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen sb.append('='); 308674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen sb.append(get(key)); 309674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen if (it.hasNext()) { 310674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen sb.append(", "); 311674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 312674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 313674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen sb.append('}'); 314674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen return sb.toString(); 315674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen } 316674060f01e9090cd21b3c5656cc3204912ad17a6Jon Boekenoogen} 317