View Javadoc
1 /* 2 * The Apache Software License, Version 1.1 3 * 4 * Copyright (c) 2002 The Apache Software Foundation. All rights 5 * reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 19 * 3. The end-user documentation included with the redistribution, 20 * if any, must include the following acknowledgment: 21 * "This product includes software developed by the 22 * Apache Software Foundation (http://www.apache.org/)." 23 * Alternately, this acknowledgment may appear in the software itself, 24 * if and wherever such third-party acknowledgments normally appear. 25 * 26 * 4. The names "Apache" and "Apache Software Foundation" must 27 * not be used to endorse or promote products derived from this 28 * software without prior written permission. For written 29 * permission, please contact apache@apache.org. 30 * 31 * 5. Products derived from this software may not be called "Apache", 32 * nor may "Apache" appear in their name, without prior written 33 * permission of the Apache Software Foundation. 34 * 35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 38 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 42 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 46 * SUCH DAMAGE. 47 * ==================================================================== 48 * 49 * This software consists of voluntary contributions made by many 50 * individuals on behalf of the Apache Software Foundation. For more 51 * information on the Apache Software Foundation, please see 52 * <http://www.apache.org/>;. 53 */ 54 package net.sf.cglib.beans; 55 56 import java.beans.*; 57 import java.lang.reflect.Constructor; 58 import java.lang.reflect.Method; 59 import java.util.*; 60 import net.sf.cglib.core.*; 61 import org.objectweb.asm.ClassVisitor; 62 63 /*** 64 * A <code>Map</code>-based view of a JavaBean. The default set of keys is the 65 * union of all property names (getters or setters). An attempt to set 66 * a read-only property will be ignored, and write-only properties will 67 * be returned as <code>null</code>. Removal of objects is not a 68 * supported (the key set is fixed). 69 * @author Chris Nokleberg 70 */ 71 abstract public class BeanMap implements Map { 72 /*** 73 * Limit the properties reflected in the key set of the map 74 * to readable properties. 75 * @see BeanMap.Generator#setRequire 76 */ 77 public static final int REQUIRE_GETTER = 1; 78 79 /*** 80 * Limit the properties reflected in the key set of the map 81 * to writable properties. 82 * @see BeanMap.Generator#setRequire 83 */ 84 public static final int REQUIRE_SETTER = 2; 85 86 /*** 87 * Helper method to create a new <code>BeanMap</code>. For finer 88 * control over the generated instance, use a new instance of 89 * <code>BeanMap.Generator</code> instead of this static method. 90 * @param bean the JavaBean underlying the map 91 * @return a new <code>BeanMap</code> instance 92 */ 93 public static BeanMap create(Object bean) { 94 Generator gen = new Generator(); 95 gen.setBean(bean); 96 return gen.create(); 97 } 98 99 public static class Generator extends AbstractClassGenerator { 100 private static final Source SOURCE = new Source(BeanMap.class.getName()); 101 102 private static final BeanMapKey KEY_FACTORY = 103 (BeanMapKey)KeyFactory.create(BeanMapKey.class, KeyFactory.CLASS_BY_NAME); 104 105 interface BeanMapKey { 106 public Object newInstance(Class type, int require); 107 } 108 109 private Object bean; 110 private Class beanClass; 111 private int require; 112 113 public Generator() { 114 super(SOURCE); 115 } 116 117 /*** 118 * Set the bean that the generated map should reflect. The bean may be swapped 119 * out for another bean of the same type using {@link #setBean}. 120 * Calling this method overrides any value previously set using {@link #setBeanClass}. 121 * You must call either this method or {@link #setBeanClass} before {@link #create}. 122 * @param bean the initial bean 123 */ 124 public void setBean(Object bean) { 125 this.bean = bean; 126 if (bean != null) 127 beanClass = bean.getClass(); 128 } 129 130 /*** 131 * Set the class of the bean that the generated map should support. 132 * You must call either this method or {@link #setBeanClass} before {@link #create}. 133 * @param beanClass the class of the bean 134 */ 135 public void setBeanClass(Class beanClass) { 136 this.beanClass = beanClass; 137 } 138 139 /*** 140 * Limit the properties reflected by the generated map. 141 * @param require any combination of {@link #REQUIRE_GETTER} and 142 * {@link #REQUIRE_SETTER}; default is zero (any property allowed) 143 */ 144 public void setRequire(int require) { 145 this.require = require; 146 } 147 148 protected ClassLoader getDefaultClassLoader() { 149 return beanClass.getClassLoader(); 150 } 151 152 /*** 153 * Create a new instance of the <code>BeanMap</code>. An existing 154 * generated class will be reused if possible. 155 */ 156 public BeanMap create() { 157 if (beanClass == null) 158 throw new IllegalArgumentException("Class of bean unknown"); 159 setNamePrefix(beanClass.getName()); 160 return (BeanMap)super.create(KEY_FACTORY.newInstance(beanClass, require)); 161 } 162 163 public void generateClass(ClassVisitor v) throws Exception { 164 new BeanMapEmitter(v, getClassName(), beanClass, require); 165 } 166 167 protected Object firstInstance(Class type) { 168 return ((BeanMap)ReflectUtils.newInstance(type)).newInstance(bean); 169 } 170 171 protected Object nextInstance(Object instance) { 172 return ((BeanMap)instance).newInstance(bean); 173 } 174 } 175 176 /*** 177 * Create a new <code>BeanMap</code> instance using the specified bean. 178 * This is faster than using the {@link #create} static method. 179 * @param bean the JavaBean underlying the map 180 * @return a new <code>BeanMap</code> instance 181 */ 182 abstract public BeanMap newInstance(Object bean); 183 184 /*** 185 * Get the type of a property. 186 * @param name the name of the JavaBean property 187 * @return the type of the property, or null if the property does not exist 188 */ 189 abstract public Class getPropertyType(String name); 190 191 protected Object bean; 192 193 protected BeanMap() { 194 } 195 196 protected BeanMap(Object bean) { 197 setBean(bean); 198 } 199 200 public Object get(Object key) { 201 return get(bean, key); 202 } 203 204 public Object put(Object key, Object value) { 205 return put(bean, key, value); 206 } 207 208 /*** 209 * Get the property of a bean. This allows a <code>BeanMap</code> 210 * to be used statically for multiple beans--the bean instance tied to the 211 * map is ignored and the bean passed to this method is used instead. 212 * @param bean the bean to query; must be compatible with the type of 213 * this <code>BeanMap</code> 214 * @param key must be a String 215 * @return the current value, or null if there is no matching property 216 */ 217 abstract public Object get(Object bean, Object key); 218 219 /*** 220 * Set the property of a bean. This allows a <code>BeanMap</code> 221 * to be used statically for multiple beans--the bean instance tied to the 222 * map is ignored and the bean passed to this method is used instead. 223 * @param key must be a String 224 * @return the old value, if there was one, or null 225 */ 226 abstract public Object put(Object bean, Object key, Object value); 227 228 /*** 229 * Change the underlying bean this map should use. 230 * @param bean the new JavaBean 231 * @see #getBean 232 */ 233 public void setBean(Object bean) { 234 this.bean = bean; 235 } 236 237 /*** 238 * Return the bean currently in use by this map. 239 * @return the current JavaBean 240 * @see #setBean 241 */ 242 public Object getBean() { 243 return bean; 244 } 245 246 public void clear() { 247 throw new UnsupportedOperationException(); 248 } 249 250 public boolean containsKey(Object key) { 251 return keySet().contains(key); 252 } 253 254 public boolean containsValue(Object value) { 255 for (Iterator it = keySet().iterator(); it.hasNext();) { 256 Object v = get(it.next()); 257 if (((value == null) && (v == null)) || value.equals(v)) 258 return true; 259 } 260 return false; 261 } 262 263 public int size() { 264 return keySet().size(); 265 } 266 267 public boolean isEmpty() { 268 return size() == 0; 269 } 270 271 public Object remove(Object key) { 272 throw new UnsupportedOperationException(); 273 } 274 275 public void putAll(Map t) { 276 for (Iterator it = t.keySet().iterator(); it.hasNext();) { 277 Object key = it.next(); 278 put(key, t.get(key)); 279 } 280 } 281 282 public boolean equals(Object o) { 283 if (o == null || !(o instanceof Map)) { 284 return false; 285 } 286 Map other = (Map)o; 287 if (size() != other.size()) { 288 return false; 289 } 290 for (Iterator it = keySet().iterator(); it.hasNext();) { 291 Object key = it.next(); 292 if (!other.containsKey(key)) { 293 return false; 294 } 295 Object v1 = get(key); 296 Object v2 = other.get(key); 297 if (!((v1 == null) ? v2 == null : v1.equals(v2))) { 298 return false; 299 } 300 } 301 return true; 302 } 303 304 public int hashCode() { 305 int code = 0; 306 for (Iterator it = keySet().iterator(); it.hasNext();) { 307 Object key = it.next(); 308 Object value = get(key); 309 code += ((key == null) ? 0 : key.hashCode()) ^ 310 ((value == null) ? 0 : value.hashCode()); 311 } 312 return code; 313 } 314 315 // TODO: optimize 316 public Set entrySet() { 317 return Collections.unmodifiableMap(new HashMap(this)).entrySet(); 318 } 319 320 public Collection values() { 321 Set keys = keySet(); 322 List values = new ArrayList(keys.size()); 323 for (Iterator it = keys.iterator(); it.hasNext();) { 324 values.add(get(it.next())); 325 } 326 return Collections.unmodifiableCollection(values); 327 } 328 329 /* 330 * @see java.util.AbstractMap#toString 331 */ 332 public String toString() 333 { 334 StringBuffer sb = new StringBuffer(); 335 sb.append('{'); 336 for (Iterator it = keySet().iterator(); it.hasNext();) { 337 Object key = it.next(); 338 sb.append(key); 339 sb.append('='); 340 sb.append(get(key)); 341 if (it.hasNext()) { 342 sb.append(", "); 343 } 344 } 345 sb.append('}'); 346 return sb.toString(); 347 } 348 }

This page was automatically generated by Maven