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.util.*;
58 import net.sf.cglib.core.*;
59 import org.objectweb.asm.ClassVisitor;
60 import org.objectweb.asm.Label;
61 import org.objectweb.asm.Type;
62
63 class BeanMapEmitter extends ClassEmitter {
64 private static final Signature CSTRUCT_OBJECT =
65 TypeUtils.parseConstructor("Object");
66 private static final Signature CSTRUCT_STRING_ARRAY =
67 TypeUtils.parseConstructor("String[]");
68 private static final Signature BEAN_MAP_GET =
69 TypeUtils.parseSignature("Object get(Object, Object)");
70 private static final Signature BEAN_MAP_PUT =
71 TypeUtils.parseSignature("Object put(Object, Object, Object)");
72 private static final Signature KEY_SET =
73 TypeUtils.parseSignature("java.util.Set keySet()");
74 private static final Signature NEW_INSTANCE =
75 TypeUtils.parseSignature("net.sf.cglib.beans.BeanMap newInstance(Object)");
76 private static final Signature GET_PROPERTY_TYPE =
77 TypeUtils.parseSignature("Class getPropertyType(String)");
78 private static final Type BEAN_MAP =
79 TypeUtils.parseType("net.sf.cglib.beans.BeanMap");
80 private static final Type FIXED_KEY_SET =
81 TypeUtils.parseType("net.sf.cglib.beans.FixedKeySet");
82
83 public BeanMapEmitter(ClassVisitor v, String className, Class type, int require) {
84 super(v);
85
86 begin_class(Constants.ACC_PUBLIC, className, BEAN_MAP, null, Constants.SOURCE_FILE);
87 EmitUtils.null_constructor(this);
88 EmitUtils.factory_method(this, NEW_INSTANCE);
89 generateConstructor();
90
91 Map getters = makePropertyMap(ReflectUtils.getBeanGetters(type));
92 Map setters = makePropertyMap(ReflectUtils.getBeanSetters(type));
93 Map allProps = new HashMap();
94 allProps.putAll(getters);
95 allProps.putAll(setters);
96
97 if (require != 0) {
98 for (Iterator it = allProps.keySet().iterator(); it.hasNext();) {
99 String name = (String)it.next();
100 if ((((require & BeanMap.REQUIRE_GETTER) != 0) && !getters.containsKey(name)) ||
101 (((require & BeanMap.REQUIRE_SETTER) != 0) && !setters.containsKey(name))) {
102 it.remove();
103 getters.remove(name);
104 setters.remove(name);
105 }
106 }
107 }
108 generateGet(type, getters);
109 generatePut(type, setters);
110
111 String[] allNames = getNames(allProps);
112 generateKeySet(allNames);
113 generateGetPropertyType(allProps, allNames);
114 end_class();
115 }
116
117 private Map makePropertyMap(PropertyDescriptor[] props) {
118 Map names = new HashMap();
119 for (int i = 0; i < props.length; i++) {
120 names.put(((PropertyDescriptor)props[i]).getName(), props[i]);
121 }
122 return names;
123 }
124
125 private String[] getNames(Map propertyMap) {
126 return (String[])propertyMap.keySet().toArray(new String[propertyMap.size()]);
127 }
128
129 private void generateConstructor() {
130 CodeEmitter e = begin_method(Constants.ACC_PUBLIC, CSTRUCT_OBJECT, null, null);
131 e.load_this();
132 e.load_arg(0);
133 e.super_invoke_constructor(CSTRUCT_OBJECT);
134 e.return_value();
135 e.end_method();
136 }
137
138 private void generateGet(Class type, final Map getters) {
139 final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, BEAN_MAP_GET, null, null);
140 e.load_arg(0);
141 e.checkcast(Type.getType(type));
142 e.load_arg(1);
143 e.checkcast(Constants.TYPE_STRING);
144 EmitUtils.string_switch(e, getNames(getters), Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() {
145 public void processCase(Object key, Label end) {
146 PropertyDescriptor pd = (PropertyDescriptor)getters.get(key);
147 e.invoke(pd.getReadMethod());
148 e.box(Type.getType(pd.getReadMethod().getReturnType()));
149 e.return_value();
150 }
151 public void processDefault() {
152 e.aconst_null();
153 e.return_value();
154 }
155 });
156 e.end_method();
157 }
158
159 private void generatePut(Class type, final Map setters) {
160 final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, BEAN_MAP_PUT, null, null);
161 e.load_arg(0);
162 e.checkcast(Type.getType(type));
163 e.load_arg(1);
164 e.checkcast(Constants.TYPE_STRING);
165 EmitUtils.string_switch(e, getNames(setters), Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() {
166 public void processCase(Object key, Label end) {
167 PropertyDescriptor pd = (PropertyDescriptor)setters.get(key);
168 if (pd.getReadMethod() == null) {
169 e.aconst_null();
170 } else {
171 e.dup();
172 e.invoke(pd.getReadMethod());
173 e.box(Type.getType(pd.getReadMethod().getReturnType()));
174 }
175 e.swap(); // move old value behind bean
176 e.load_arg(2); // new value
177 e.unbox(Type.getType(pd.getWriteMethod().getParameterTypes()[0]));
178 e.invoke(pd.getWriteMethod());
179 e.return_value();
180 }
181 public void processDefault() {
182 // fall-through
183 }
184 });
185 e.aconst_null();
186 e.return_value();
187 e.end_method();
188 }
189
190 private void generateKeySet(String[] allNames) {
191 // static initializer
192 declare_field(Constants.ACC_STATIC | Constants.ACC_PRIVATE, "keys", FIXED_KEY_SET, null, null);
193
194 CodeEmitter e = begin_static();
195 e.new_instance(FIXED_KEY_SET);
196 e.dup();
197 EmitUtils.push_array(e, allNames);
198 e.invoke_constructor(FIXED_KEY_SET, CSTRUCT_STRING_ARRAY);
199 e.putfield("keys");
200 e.return_value();
201 e.end_method();
202
203 // keySet
204 e = begin_method(Constants.ACC_PUBLIC, KEY_SET, null, null);
205 e.load_this();
206 e.getfield("keys");
207 e.return_value();
208 e.end_method();
209 }
210
211 private void generateGetPropertyType(final Map allProps, String[] allNames) {
212 final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, GET_PROPERTY_TYPE, null, null);
213 e.load_arg(0);
214 EmitUtils.string_switch(e, allNames, Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() {
215 public void processCase(Object key, Label end) {
216 PropertyDescriptor pd = (PropertyDescriptor)allProps.get(key);
217 EmitUtils.load_class(e, Type.getType(pd.getPropertyType()));
218 e.return_value();
219 }
220 public void processDefault() {
221 e.aconst_null();
222 e.return_value();
223 }
224 });
225 e.end_method();
226 }
227 }
This page was automatically generated by Maven