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