001: /*
002: * Copyright 2003,2004 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package net.sf.cglib.beans;
017:
018: import java.beans.*;
019: import java.util.*;
020: import net.sf.cglib.core.*;
021: import org.objectweb.asm.ClassVisitor;
022: import org.objectweb.asm.Label;
023: import org.objectweb.asm.Type;
024:
025: class BeanMapEmitter extends ClassEmitter {
026: private static final Type BEAN_MAP = TypeUtils
027: .parseType("net.sf.cglib.beans.BeanMap");
028: private static final Type FIXED_KEY_SET = TypeUtils
029: .parseType("net.sf.cglib.beans.FixedKeySet");
030: private static final Signature CSTRUCT_OBJECT = TypeUtils
031: .parseConstructor("Object");
032: private static final Signature CSTRUCT_STRING_ARRAY = TypeUtils
033: .parseConstructor("String[]");
034: private static final Signature BEAN_MAP_GET = TypeUtils
035: .parseSignature("Object get(Object, Object)");
036: private static final Signature BEAN_MAP_PUT = TypeUtils
037: .parseSignature("Object put(Object, Object, Object)");
038: private static final Signature KEY_SET = TypeUtils
039: .parseSignature("java.util.Set keySet()");
040: private static final Signature NEW_INSTANCE = new Signature(
041: "newInstance", BEAN_MAP,
042: new Type[] { Constants.TYPE_OBJECT });
043: private static final Signature GET_PROPERTY_TYPE = TypeUtils
044: .parseSignature("Class getPropertyType(String)");
045:
046: public BeanMapEmitter(ClassVisitor v, String className, Class type,
047: int require) {
048: super (v);
049:
050: begin_class(Constants.V1_2, Constants.ACC_PUBLIC, className,
051: BEAN_MAP, null, Constants.SOURCE_FILE);
052: EmitUtils.null_constructor(this );
053: EmitUtils.factory_method(this , NEW_INSTANCE);
054: generateConstructor();
055:
056: Map getters = makePropertyMap(ReflectUtils.getBeanGetters(type));
057: Map setters = makePropertyMap(ReflectUtils.getBeanSetters(type));
058: Map allProps = new HashMap();
059: allProps.putAll(getters);
060: allProps.putAll(setters);
061:
062: if (require != 0) {
063: for (Iterator it = allProps.keySet().iterator(); it
064: .hasNext();) {
065: String name = (String) it.next();
066: if ((((require & BeanMap.REQUIRE_GETTER) != 0) && !getters
067: .containsKey(name))
068: || (((require & BeanMap.REQUIRE_SETTER) != 0) && !setters
069: .containsKey(name))) {
070: it.remove();
071: getters.remove(name);
072: setters.remove(name);
073: }
074: }
075: }
076: generateGet(type, getters);
077: generatePut(type, setters);
078:
079: String[] allNames = getNames(allProps);
080: generateKeySet(allNames);
081: generateGetPropertyType(allProps, allNames);
082: end_class();
083: }
084:
085: private Map makePropertyMap(PropertyDescriptor[] props) {
086: Map names = new HashMap();
087: for (int i = 0; i < props.length; i++) {
088: names.put(((PropertyDescriptor) props[i]).getName(),
089: props[i]);
090: }
091: return names;
092: }
093:
094: private String[] getNames(Map propertyMap) {
095: return (String[]) propertyMap.keySet().toArray(
096: new String[propertyMap.size()]);
097: }
098:
099: private void generateConstructor() {
100: CodeEmitter e = begin_method(Constants.ACC_PUBLIC,
101: CSTRUCT_OBJECT, null);
102: e.load_this ();
103: e.load_arg(0);
104: e.super _invoke_constructor(CSTRUCT_OBJECT);
105: e.return_value();
106: e.end_method();
107: }
108:
109: private void generateGet(Class type, final Map getters) {
110: final CodeEmitter e = begin_method(Constants.ACC_PUBLIC,
111: BEAN_MAP_GET, null);
112: e.load_arg(0);
113: e.checkcast(Type.getType(type));
114: e.load_arg(1);
115: e.checkcast(Constants.TYPE_STRING);
116: EmitUtils.string_switch(e, getNames(getters),
117: Constants.SWITCH_STYLE_HASH,
118: new ObjectSwitchCallback() {
119: public void processCase(Object key, Label end) {
120: PropertyDescriptor pd = (PropertyDescriptor) getters
121: .get(key);
122: MethodInfo method = ReflectUtils
123: .getMethodInfo(pd.getReadMethod());
124: e.invoke(method);
125: e.box(method.getSignature().getReturnType());
126: e.return_value();
127: }
128:
129: public void processDefault() {
130: e.aconst_null();
131: e.return_value();
132: }
133: });
134: e.end_method();
135: }
136:
137: private void generatePut(Class type, final Map setters) {
138: final CodeEmitter e = begin_method(Constants.ACC_PUBLIC,
139: BEAN_MAP_PUT, 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(setters),
145: Constants.SWITCH_STYLE_HASH,
146: new ObjectSwitchCallback() {
147: public void processCase(Object key, Label end) {
148: PropertyDescriptor pd = (PropertyDescriptor) setters
149: .get(key);
150: if (pd.getReadMethod() == null) {
151: e.aconst_null();
152: } else {
153: MethodInfo read = ReflectUtils
154: .getMethodInfo(pd.getReadMethod());
155: e.dup();
156: e.invoke(read);
157: e.box(read.getSignature().getReturnType());
158: }
159: e.swap(); // move old value behind bean
160: e.load_arg(2); // new value
161: MethodInfo write = ReflectUtils
162: .getMethodInfo(pd.getWriteMethod());
163: e
164: .unbox(write.getSignature()
165: .getArgumentTypes()[0]);
166: e.invoke(write);
167: e.return_value();
168: }
169:
170: public void processDefault() {
171: // fall-through
172: }
173: });
174: e.aconst_null();
175: e.return_value();
176: e.end_method();
177: }
178:
179: private void generateKeySet(String[] allNames) {
180: // static initializer
181: declare_field(Constants.ACC_STATIC | Constants.ACC_PRIVATE,
182: "keys", FIXED_KEY_SET, null);
183:
184: CodeEmitter e = begin_static();
185: e.new_instance(FIXED_KEY_SET);
186: e.dup();
187: EmitUtils.push_array(e, allNames);
188: e.invoke_constructor(FIXED_KEY_SET, CSTRUCT_STRING_ARRAY);
189: e.putfield("keys");
190: e.return_value();
191: e.end_method();
192:
193: // keySet
194: e = begin_method(Constants.ACC_PUBLIC, KEY_SET, null);
195: e.load_this ();
196: e.getfield("keys");
197: e.return_value();
198: e.end_method();
199: }
200:
201: private void generateGetPropertyType(final Map allProps,
202: String[] allNames) {
203: final CodeEmitter e = begin_method(Constants.ACC_PUBLIC,
204: GET_PROPERTY_TYPE, null);
205: e.load_arg(0);
206: EmitUtils.string_switch(e, allNames,
207: Constants.SWITCH_STYLE_HASH,
208: new ObjectSwitchCallback() {
209: public void processCase(Object key, Label end) {
210: PropertyDescriptor pd = (PropertyDescriptor) allProps
211: .get(key);
212: EmitUtils.load_class(e, Type.getType(pd
213: .getPropertyType()));
214: e.return_value();
215: }
216:
217: public void processDefault() {
218: e.aconst_null();
219: e.return_value();
220: }
221: });
222: e.end_method();
223: }
224: }
|