KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > cglib > beans > BeanMap


1 /*
2  * Copyright 2003,2004 The Apache Software Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package net.sf.cglib.beans;
17
18 import java.beans.*;
19 import java.lang.reflect.Constructor JavaDoc;
20 import java.lang.reflect.Method JavaDoc;
21 import java.util.*;
22 import net.sf.cglib.core.*;
23 import org.objectweb.asm.ClassVisitor;
24
25 /**
26  * A <code>Map</code>-based view of a JavaBean. The default set of keys is the
27  * union of all property names (getters or setters). An attempt to set
28  * a read-only property will be ignored, and write-only properties will
29  * be returned as <code>null</code>. Removal of objects is not a
30  * supported (the key set is fixed).
31  * @author Chris Nokleberg
32  */

33 abstract public class BeanMap implements Map {
34     /**
35      * Limit the properties reflected in the key set of the map
36      * to readable properties.
37      * @see BeanMap.Generator#setRequire
38      */

39     public static final int REQUIRE_GETTER = 1;
40
41     /**
42      * Limit the properties reflected in the key set of the map
43      * to writable properties.
44      * @see BeanMap.Generator#setRequire
45      */

46     public static final int REQUIRE_SETTER = 2;
47     
48     /**
49      * Helper method to create a new <code>BeanMap</code>. For finer
50      * control over the generated instance, use a new instance of
51      * <code>BeanMap.Generator</code> instead of this static method.
52      * @param bean the JavaBean underlying the map
53      * @return a new <code>BeanMap</code> instance
54      */

55     public static BeanMap create(Object JavaDoc bean) {
56         Generator gen = new Generator();
57         gen.setBean(bean);
58         return gen.create();
59     }
60
61     public static class Generator extends AbstractClassGenerator {
62         private static final Source SOURCE = new Source(BeanMap.class.getName());
63
64         private static final BeanMapKey KEY_FACTORY =
65           (BeanMapKey)KeyFactory.create(BeanMapKey.class, KeyFactory.CLASS_BY_NAME);
66
67         interface BeanMapKey {
68             public Object JavaDoc newInstance(Class JavaDoc type, int require);
69         }
70         
71         private Object JavaDoc bean;
72         private Class JavaDoc beanClass;
73         private int require;
74         
75         public Generator() {
76             super(SOURCE);
77         }
78
79         /**
80          * Set the bean that the generated map should reflect. The bean may be swapped
81          * out for another bean of the same type using {@link #setBean}.
82          * Calling this method overrides any value previously set using {@link #setBeanClass}.
83          * You must call either this method or {@link #setBeanClass} before {@link #create}.
84          * @param bean the initial bean
85          */

86         public void setBean(Object JavaDoc bean) {
87             this.bean = bean;
88             if (bean != null)
89                 beanClass = bean.getClass();
90         }
91
92         /**
93          * Set the class of the bean that the generated map should support.
94          * You must call either this method or {@link #setBeanClass} before {@link #create}.
95          * @param beanClass the class of the bean
96          */

97         public void setBeanClass(Class JavaDoc beanClass) {
98             this.beanClass = beanClass;
99         }
100
101         /**
102          * Limit the properties reflected by the generated map.
103          * @param require any combination of {@link #REQUIRE_GETTER} and
104          * {@link #REQUIRE_SETTER}; default is zero (any property allowed)
105          */

106         public void setRequire(int require) {
107             this.require = require;
108         }
109
110         protected ClassLoader JavaDoc getDefaultClassLoader() {
111             return beanClass.getClassLoader();
112         }
113
114         /**
115          * Create a new instance of the <code>BeanMap</code>. An existing
116          * generated class will be reused if possible.
117          */

118         public BeanMap create() {
119             if (beanClass == null)
120                 throw new IllegalArgumentException JavaDoc("Class of bean unknown");
121             setNamePrefix(beanClass.getName());
122             return (BeanMap)super.create(KEY_FACTORY.newInstance(beanClass, require));
123         }
124
125         public void generateClass(ClassVisitor v) throws Exception JavaDoc {
126             new BeanMapEmitter(v, getClassName(), beanClass, require);
127         }
128
129         protected Object JavaDoc firstInstance(Class JavaDoc type) {
130             return ((BeanMap)ReflectUtils.newInstance(type)).newInstance(bean);
131         }
132
133         protected Object JavaDoc nextInstance(Object JavaDoc instance) {
134             return ((BeanMap)instance).newInstance(bean);
135         }
136     }
137
138     /**
139      * Create a new <code>BeanMap</code> instance using the specified bean.
140      * This is faster than using the {@link #create} static method.
141      * @param bean the JavaBean underlying the map
142      * @return a new <code>BeanMap</code> instance
143      */

144     abstract public BeanMap newInstance(Object JavaDoc bean);
145
146     /**
147      * Get the type of a property.
148      * @param name the name of the JavaBean property
149      * @return the type of the property, or null if the property does not exist
150      */

151     abstract public Class JavaDoc getPropertyType(String JavaDoc name);
152
153     protected Object JavaDoc bean;
154
155     protected BeanMap() {
156     }
157
158     protected BeanMap(Object JavaDoc bean) {
159         setBean(bean);
160     }
161
162     public Object JavaDoc get(Object JavaDoc key) {
163         return get(bean, key);
164     }
165
166     public Object JavaDoc put(Object JavaDoc key, Object JavaDoc value) {
167         return put(bean, key, value);
168     }
169
170     /**
171      * Get the property of a bean. This allows a <code>BeanMap</code>
172      * to be used statically for multiple beans--the bean instance tied to the
173      * map is ignored and the bean passed to this method is used instead.
174      * @param bean the bean to query; must be compatible with the type of
175      * this <code>BeanMap</code>
176      * @param key must be a String
177      * @return the current value, or null if there is no matching property
178      */

179     abstract public Object JavaDoc get(Object JavaDoc bean, Object JavaDoc key);
180
181     /**
182      * Set the property of a bean. This allows a <code>BeanMap</code>
183      * to be used statically for multiple beans--the bean instance tied to the
184      * map is ignored and the bean passed to this method is used instead.
185      * @param key must be a String
186      * @return the old value, if there was one, or null
187      */

188     abstract public Object JavaDoc put(Object JavaDoc bean, Object JavaDoc key, Object JavaDoc value);
189
190     /**
191      * Change the underlying bean this map should use.
192      * @param bean the new JavaBean
193      * @see #getBean
194      */

195     public void setBean(Object JavaDoc bean) {
196         this.bean = bean;
197     }
198
199     /**
200      * Return the bean currently in use by this map.
201      * @return the current JavaBean
202      * @see #setBean
203      */

204     public Object JavaDoc getBean() {
205         return bean;
206     }
207
208     public void clear() {
209         throw new UnsupportedOperationException JavaDoc();
210     }
211
212     public boolean containsKey(Object JavaDoc key) {
213         return keySet().contains(key);
214     }
215
216     public boolean containsValue(Object JavaDoc value) {
217         for (Iterator it = keySet().iterator(); it.hasNext();) {
218             Object JavaDoc v = get(it.next());
219             if (((value == null) && (v == null)) || value.equals(v))
220                 return true;
221         }
222         return false;
223     }
224
225     public int size() {
226         return keySet().size();
227     }
228
229     public boolean isEmpty() {
230         return size() == 0;
231     }
232
233     public Object JavaDoc remove(Object JavaDoc key) {
234         throw new UnsupportedOperationException JavaDoc();
235     }
236
237     public void putAll(Map t) {
238         for (Iterator it = t.keySet().iterator(); it.hasNext();) {
239             Object JavaDoc key = it.next();
240             put(key, t.get(key));
241         }
242     }
243
244     public boolean equals(Object JavaDoc o) {
245         if (o == null || !(o instanceof Map)) {
246             return false;
247         }
248         Map other = (Map)o;
249         if (size() != other.size()) {
250             return false;
251         }
252         for (Iterator it = keySet().iterator(); it.hasNext();) {
253             Object JavaDoc key = it.next();
254             if (!other.containsKey(key)) {
255                 return false;
256             }
257             Object JavaDoc v1 = get(key);
258             Object JavaDoc v2 = other.get(key);
259             if (!((v1 == null) ? v2 == null : v1.equals(v2))) {
260                 return false;
261             }
262         }
263         return true;
264     }
265
266     public int hashCode() {
267         int code = 0;
268         for (Iterator it = keySet().iterator(); it.hasNext();) {
269             Object JavaDoc key = it.next();
270             Object JavaDoc value = get(key);
271             code += ((key == null) ? 0 : key.hashCode()) ^
272                 ((value == null) ? 0 : value.hashCode());
273         }
274         return code;
275     }
276
277     // TODO: optimize
278
public Set entrySet() {
279         HashMap copy = new HashMap();
280         for (Iterator it = keySet().iterator(); it.hasNext();) {
281             Object JavaDoc key = it.next();
282             copy.put(key, get(key));
283         }
284         return Collections.unmodifiableMap(copy).entrySet();
285     }
286
287     public Collection values() {
288         Set keys = keySet();
289         List values = new ArrayList(keys.size());
290         for (Iterator it = keys.iterator(); it.hasNext();) {
291             values.add(get(it.next()));
292         }
293         return Collections.unmodifiableCollection(values);
294     }
295
296     /*
297      * @see java.util.AbstractMap#toString
298      */

299     public String JavaDoc toString()
300     {
301         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
302         sb.append('{');
303         for (Iterator it = keySet().iterator(); it.hasNext();) {
304             Object JavaDoc key = it.next();
305             sb.append(key);
306             sb.append('=');
307             sb.append(get(key));
308             if (it.hasNext()) {
309                 sb.append(", ");
310             }
311         }
312         sb.append('}');
313         return sb.toString();
314     }
315 }
316
Popular Tags