2
* Copyright 2003,2004 The Apache Software Foundation
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
8
* http://www.apache.org/licenses/LICENSE-2.0
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.
16
package net.sf.cglib.beans;
19
import java.lang.reflect.Constructor;
20
import java.lang.reflect.Method;
22
import net.sf.cglib.core.*;
23
import org.objectweb.asm.ClassVisitor;
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
33
abstract public class BeanMap implements Map {
35
* Limit the properties reflected in the key set of the map
36
* to readable properties.
37
* @see BeanMap.Generator#setRequire
39
public static final int REQUIRE_GETTER = 1;
42
* Limit the properties reflected in the key set of the map
43
* to writable properties.
44
* @see BeanMap.Generator#setRequire
46
public static final int REQUIRE_SETTER = 2;
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
55
public static BeanMap create(Object bean) {
56
Generator gen = new Generator();
61
public static class Generator extends AbstractClassGenerator {
62
private static final Source SOURCE = new Source(BeanMap.class.getName());
64
private static final BeanMapKey KEY_FACTORY =
65
(BeanMapKey)KeyFactory.create(BeanMapKey.class, KeyFactory.CLASS_BY_NAME);
67
interface BeanMapKey {
68
public Object newInstance(Class type, int require);
72
private Class beanClass;
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
86
public void setBean(Object bean) {
89
beanClass = bean.getClass();
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
97
public void setBeanClass(Class beanClass) {
98
this.beanClass = beanClass;
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)
106
public void setRequire(int require) {
107
this.require = require;
110
protected ClassLoader getDefaultClassLoader() {
111
return beanClass.getClassLoader();
115
* Create a new instance of the <code>BeanMap</code>. An existing
116
* generated class will be reused if possible.
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));
125
public void generateClass(ClassVisitor v) throws Exception {
126
new BeanMapEmitter(v, getClassName(), beanClass, require);
129
protected Object firstInstance(Class type) {
130
return ((BeanMap)ReflectUtils.newInstance(type)).newInstance(bean);
133
protected Object nextInstance(Object instance) {
134
return ((BeanMap)instance).newInstance(bean);
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
144
abstract public BeanMap newInstance(Object bean);
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
151
abstract public Class getPropertyType(String name);
153
protected Object bean;
155
protected BeanMap() {
158
protected BeanMap(Object bean) {
162
public Object get(Object key) {
163
return get(bean, key);
166
public Object put(Object key, Object value) {
167
return put(bean, key, value);
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
179
abstract public Object get(Object bean, Object key);
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
188
abstract public Object put(Object bean, Object key, Object value);
191
* Change the underlying bean this map should use.
192
* @param bean the new JavaBean
195
public void setBean(Object bean) {
200
* Return the bean currently in use by this map.
201
* @return the current JavaBean
204
public Object getBean() {
208
public void clear() {
209
throw new UnsupportedOperationException();
212
public boolean containsKey(Object key) {
213
return keySet().contains(key);
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))
226
return keySet().size();
229
public boolean isEmpty() {
233
public Object remove(Object key) {
234
throw new UnsupportedOperationException();
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));
244
public boolean equals(Object o) {
245
if (o == null || !(o instanceof Map)) {
249
if (size() != other.size()) {
252
for (Iterator it = keySet().iterator(); it.hasNext();) {
253
Object key = it.next();
254
if (!other.containsKey(key)) {
257
Object v1 = get(key);
258
Object v2 = other.get(key);
259
if (!((v1 == null) ? v2 == null : v1.equals(v2))) {
266
public int hashCode() {
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());
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));
284
return Collections.unmodifiableMap(copy).entrySet();
287
public Collection values() {
289
List values = new ArrayList(keys.size());
290
for (Iterator it = keys.iterator(); it.hasNext();) {
291
values.add(get(it.next()));
293
return Collections.unmodifiableCollection(values);
297
* @see java.util.AbstractMap#toString
299
public String toString()
301
StringBuffer sb = new StringBuffer();
303
for (Iterator it = keySet().iterator(); it.hasNext();) {
304
Object key = it.next();
313
return sb.toString();