KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > cglib > transform > impl > FieldProviderTransformer


1 /*
2  * Copyright 2003 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.transform.impl;
17
18 import net.sf.cglib.transform.*;
19 import java.util.*;
20 import net.sf.cglib.core.*;
21 import org.objectweb.asm.Attribute;
22 import org.objectweb.asm.Label;
23 import org.objectweb.asm.Type;
24
25 public class FieldProviderTransformer extends ClassEmitterTransformer {
26     
27     private static final String JavaDoc FIELD_NAMES = "CGLIB$FIELD_NAMES";
28     private static final String JavaDoc FIELD_TYPES = "CGLIB$FIELD_TYPES";
29     
30     private static final Type FIELD_PROVIDER =
31       TypeUtils.parseType("net.sf.cglib.transform.impl.FieldProvider");
32     private static final Type ILLEGAL_ARGUMENT_EXCEPTION =
33       TypeUtils.parseType("IllegalArgumentException");
34     private static final Signature PROVIDER_GET =
35       TypeUtils.parseSignature("Object getField(String)");
36     private static final Signature PROVIDER_SET =
37       TypeUtils.parseSignature("void setField(String, Object)");
38     private static final Signature PROVIDER_SET_BY_INDEX =
39       TypeUtils.parseSignature("void setField(int, Object)");
40     private static final Signature PROVIDER_GET_BY_INDEX =
41       TypeUtils.parseSignature("Object getField(int)");
42     private static final Signature PROVIDER_GET_TYPES =
43       TypeUtils.parseSignature("Class[] getFieldTypes()");
44     private static final Signature PROVIDER_GET_NAMES =
45       TypeUtils.parseSignature("String[] getFieldNames()");
46     
47     private int access;
48     private Map fields;
49     
50     public void begin_class(int version, int access, String JavaDoc className, Type superType, Type[] interfaces, String JavaDoc sourceFile) {
51         if (!TypeUtils.isAbstract(access)) {
52             interfaces = TypeUtils.add(interfaces, FIELD_PROVIDER);
53         }
54         this.access = access;
55         fields = new HashMap();
56         super.begin_class(version, access, className, superType, interfaces, sourceFile);
57     }
58
59     public void declare_field(int access, String JavaDoc name, Type type, Object JavaDoc value) {
60         super.declare_field(access, name, type, value);
61         
62         if (!TypeUtils.isStatic(access)) {
63             fields.put(name, type);
64         }
65     }
66
67     public void end_class() {
68         if (!TypeUtils.isInterface(access)) {
69             try {
70                 generate();
71             } catch (RuntimeException JavaDoc e) {
72                 throw e;
73             } catch (Exception JavaDoc e) {
74                 throw new CodeGenerationException(e);
75             }
76         }
77         super.end_class();
78     }
79
80     private void generate() throws Exception JavaDoc {
81         final String JavaDoc[] names = (String JavaDoc[])fields.keySet().toArray(new String JavaDoc[fields.size()]);
82
83         int indexes[] = new int[names.length];
84         for (int i = 0; i < indexes.length; i++) {
85             indexes[i] = i;
86         }
87         
88         super.declare_field(Constants.PRIVATE_FINAL_STATIC, FIELD_NAMES, Constants.TYPE_STRING_ARRAY, null);
89         super.declare_field(Constants.PRIVATE_FINAL_STATIC, FIELD_TYPES, Constants.TYPE_CLASS_ARRAY, null);
90
91         // use separate methods here because each process switch inner class needs a final CodeEmitter
92
initFieldProvider(names);
93         getNames();
94         getTypes();
95         getField(names);
96         setField(names);
97         setByIndex(names, indexes);
98         getByIndex(names, indexes);
99     }
100
101     private void initFieldProvider(String JavaDoc[] names) {
102         CodeEmitter e = getStaticHook();
103         EmitUtils.push_object(e, names);
104         e.putstatic(getClassType(), FIELD_NAMES, Constants.TYPE_STRING_ARRAY);
105         
106         e.push(names.length);
107         e.newarray(Constants.TYPE_CLASS);
108         e.dup();
109         for(int i = 0; i < names.length; i++ ){
110             e.dup();
111             e.push(i);
112             Type type = (Type)fields.get(names[i]);
113             EmitUtils.load_class(e, type);
114             e.aastore();
115         }
116         e.putstatic(getClassType(), FIELD_TYPES, Constants.TYPE_CLASS_ARRAY);
117     }
118
119     private void getNames() {
120         CodeEmitter e = super.begin_method(Constants.ACC_PUBLIC, PROVIDER_GET_NAMES, null);
121         e.getstatic(getClassType(), FIELD_NAMES, Constants.TYPE_STRING_ARRAY);
122         e.return_value();
123         e.end_method();
124     }
125
126     private void getTypes() {
127         CodeEmitter e = super.begin_method(Constants.ACC_PUBLIC, PROVIDER_GET_TYPES, null);
128         e.getstatic(getClassType(), FIELD_TYPES, Constants.TYPE_CLASS_ARRAY);
129         e.return_value();
130         e.end_method();
131     }
132
133     private void setByIndex(final String JavaDoc[] names, final int[] indexes) throws Exception JavaDoc {
134         final CodeEmitter e = super.begin_method(Constants.ACC_PUBLIC, PROVIDER_SET_BY_INDEX, null);
135         e.load_this();
136         e.load_arg(1);
137         e.load_arg(0);
138         e.process_switch(indexes, new ProcessSwitchCallback() {
139             public void processCase(int key, Label end) throws Exception JavaDoc {
140                 Type type = (Type)fields.get(names[key]);
141                 e.unbox(type);
142                 e.putfield(names[key]);
143                 e.return_value();
144             }
145             public void processDefault() throws Exception JavaDoc {
146                 e.throw_exception(ILLEGAL_ARGUMENT_EXCEPTION, "Unknown field index");
147             }
148         });
149         e.end_method();
150     }
151
152     private void getByIndex(final String JavaDoc[] names, final int[] indexes) throws Exception JavaDoc {
153         final CodeEmitter e = super.begin_method(Constants.ACC_PUBLIC, PROVIDER_GET_BY_INDEX, null);
154         e.load_this();
155         e.load_arg(0);
156         e.process_switch(indexes, new ProcessSwitchCallback() {
157             public void processCase(int key, Label end) throws Exception JavaDoc {
158                 Type type = (Type)fields.get(names[key]);
159                 e.getfield(names[key]);
160                 e.box(type);
161                 e.return_value();
162             }
163             public void processDefault() throws Exception JavaDoc {
164                 e.throw_exception(ILLEGAL_ARGUMENT_EXCEPTION, "Unknown field index");
165             }
166         });
167         e.end_method();
168     }
169
170     // TODO: if this is used to enhance class files SWITCH_STYLE_TRIE should be used
171
// to avoid JVM hashcode implementation incompatibilities
172
private void getField(String JavaDoc[] names) throws Exception JavaDoc {
173         final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, PROVIDER_GET, null);
174         e.load_this();
175         e.load_arg(0);
176         EmitUtils.string_switch(e, names, Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() {
177             public void processCase(Object JavaDoc key, Label end) {
178                 Type type = (Type)fields.get(key);
179                 e.getfield((String JavaDoc)key);
180                 e.box(type);
181                 e.return_value();
182             }
183             public void processDefault() {
184                 e.throw_exception(ILLEGAL_ARGUMENT_EXCEPTION, "Unknown field name");
185             }
186         });
187         e.end_method();
188     }
189
190     private void setField(String JavaDoc[] names) throws Exception JavaDoc {
191         final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, PROVIDER_SET, null);
192         e.load_this();
193         e.load_arg(1);
194         e.load_arg(0);
195         EmitUtils.string_switch(e, names, Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() {
196             public void processCase(Object JavaDoc key, Label end) {
197                 Type type = (Type)fields.get(key);
198                 e.unbox(type);
199                 e.putfield((String JavaDoc)key);
200                 e.return_value();
201             }
202             public void processDefault() {
203                 e.throw_exception(ILLEGAL_ARGUMENT_EXCEPTION, "Unknown field name");
204             }
205         });
206         e.end_method();
207     }
208 }
209
Popular Tags