~ubuntu-branches/ubuntu/trusty/cglib/trusty

« back to all changes in this revision

Viewing changes to src/proxy/net/sf/cglib/beans/BeanMap.java

  • Committer: Bazaar Package Importer
  • Author(s): Damien Raude-Morvan
  • Date: 2009-10-08 21:23:45 UTC
  • Revision ID: james.westby@ubuntu.com-20091008212345-t2zy5hv2g8o4i40k
Tags: upstream-2.2+dfsg
ImportĀ upstreamĀ versionĀ 2.2+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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;
 
20
import java.lang.reflect.Method;
 
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 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 newInstance(Class type, int require);
 
69
        }
 
70
        
 
71
        private Object bean;
 
72
        private Class 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 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 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 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("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 {
 
126
            new BeanMapEmitter(v, getClassName(), beanClass, require);
 
127
        }
 
128
 
 
129
        protected Object firstInstance(Class type) {
 
130
            return ((BeanMap)ReflectUtils.newInstance(type)).newInstance(bean);
 
131
        }
 
132
 
 
133
        protected Object nextInstance(Object 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 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 getPropertyType(String name);
 
152
 
 
153
    protected Object bean;
 
154
 
 
155
    protected BeanMap() {
 
156
    }
 
157
 
 
158
    protected BeanMap(Object bean) {
 
159
        setBean(bean);
 
160
    }
 
161
 
 
162
    public Object get(Object key) {
 
163
        return get(bean, key);
 
164
    }
 
165
 
 
166
    public Object put(Object key, Object 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 get(Object bean, Object 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 put(Object bean, Object key, Object 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 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 getBean() {
 
205
        return bean;
 
206
    }
 
207
 
 
208
    public void clear() {
 
209
        throw new UnsupportedOperationException();
 
210
    }
 
211
 
 
212
    public boolean containsKey(Object key) {
 
213
        return keySet().contains(key);
 
214
    }
 
215
 
 
216
    public boolean containsValue(Object value) {
 
217
        for (Iterator it = keySet().iterator(); it.hasNext();) {
 
218
            Object 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 remove(Object key) {
 
234
        throw new UnsupportedOperationException();
 
235
    }
 
236
 
 
237
    public void putAll(Map t) {
 
238
        for (Iterator it = t.keySet().iterator(); it.hasNext();) {
 
239
            Object key = it.next();
 
240
            put(key, t.get(key));
 
241
        }
 
242
    }
 
243
 
 
244
    public boolean equals(Object 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 key = it.next();
 
254
            if (!other.containsKey(key)) {
 
255
                return false;
 
256
            }
 
257
            Object v1 = get(key);
 
258
            Object 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 key = it.next();
 
270
            Object 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 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 toString()
 
300
    {
 
301
        StringBuffer sb = new StringBuffer();
 
302
        sb.append('{');
 
303
        for (Iterator it = keySet().iterator(); it.hasNext();) {
 
304
            Object 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
}