KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > cglib > core > ClassEmitter


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.core;
17
18 import java.io.*;
19 import java.util.*;
20 import org.objectweb.asm.*;
21
22 /**
23  * @author Juozas Baliuka, Chris Nokleberg
24  */

25 public class ClassEmitter extends ClassAdapter {
26     private ClassInfo classInfo;
27     private Map fieldInfo;
28
29     private static int hookCounter;
30     private MethodVisitor rawStaticInit;
31     private CodeEmitter staticInit;
32     private CodeEmitter staticHook;
33     private Signature staticHookSig;
34
35     public ClassEmitter(ClassVisitor cv) {
36         super(null);
37         setTarget(cv);
38     }
39
40     public ClassEmitter() {
41         super(null);
42     }
43
44     public void setTarget(ClassVisitor cv) {
45         this.cv = cv;
46         fieldInfo = new HashMap();
47
48         // just to be safe
49
staticInit = staticHook = null;
50         staticHookSig = null;
51     }
52
53     synchronized private static int getNextHook() {
54         return ++hookCounter;
55     }
56
57     public ClassInfo getClassInfo() {
58         return classInfo;
59     }
60
61     public void begin_class(int version, final int access, String JavaDoc className, final Type superType, final Type[] interfaces, String JavaDoc source) {
62         final Type classType = Type.getType("L" + className.replace('.', '/') + ";");
63         classInfo = new ClassInfo() {
64             public Type getType() {
65                 return classType;
66             }
67             public Type getSuperType() {
68                 return (superType != null) ? superType : Constants.TYPE_OBJECT;
69             }
70             public Type[] getInterfaces() {
71                 return interfaces;
72             }
73             public int getModifiers() {
74                 return access;
75             }
76         };
77         cv.visit(version,
78                  access,
79                  classInfo.getType().getInternalName(),
80                  null,
81                  classInfo.getSuperType().getInternalName(),
82                  TypeUtils.toInternalNames(interfaces));
83         if (source != null)
84             cv.visitSource(source, null);
85         init();
86     }
87
88     public CodeEmitter getStaticHook() {
89          if (TypeUtils.isInterface(getAccess())) {
90              throw new IllegalStateException JavaDoc("static hook is invalid for this class");
91          }
92          if (staticHook == null) {
93              staticHookSig = new Signature("CGLIB$STATICHOOK" + getNextHook(), "()V");
94              staticHook = begin_method(Constants.ACC_STATIC,
95                                        staticHookSig,
96                                        null);
97              if (staticInit != null) {
98                  staticInit.invoke_static_this(staticHookSig);
99              }
100          }
101          return staticHook;
102     }
103
104     protected void init() {
105     }
106
107     public int getAccess() {
108         return classInfo.getModifiers();
109     }
110
111     public Type getClassType() {
112         return classInfo.getType();
113     }
114
115     public Type getSuperType() {
116         return classInfo.getSuperType();
117     }
118
119     public void end_class() {
120         if (staticHook != null && staticInit == null) {
121             // force creation of static init
122
begin_static();
123         }
124         if (staticInit != null) {
125             staticHook.return_value();
126             staticHook.end_method();
127             rawStaticInit.visitInsn(Constants.RETURN);
128             rawStaticInit.visitMaxs(0, 0);
129             staticInit = staticHook = null;
130             staticHookSig = null;
131         }
132         cv.visitEnd();
133     }
134
135     public CodeEmitter begin_method(int access, Signature sig, Type[] exceptions) {
136         if (classInfo == null)
137             throw new IllegalStateException JavaDoc("classInfo is null! " + this);
138         MethodVisitor v = cv.visitMethod(access,
139                                          sig.getName(),
140                                          sig.getDescriptor(),
141                                          null,
142                                          TypeUtils.toInternalNames(exceptions));
143         if (sig.equals(Constants.SIG_STATIC) && !TypeUtils.isInterface(getAccess())) {
144             rawStaticInit = v;
145             MethodVisitor wrapped = new MethodAdapter(v) {
146                 public void visitMaxs(int maxStack, int maxLocals) {
147                     // ignore
148
}
149                 public void visitInsn(int insn) {
150                     if (insn != Constants.RETURN) {
151                         super.visitInsn(insn);
152                     }
153                 }
154             };
155             staticInit = new CodeEmitter(this, wrapped, access, sig, exceptions);
156             if (staticHook == null) {
157                 // force static hook creation
158
getStaticHook();
159             } else {
160                 staticInit.invoke_static_this(staticHookSig);
161             }
162             return staticInit;
163         } else if (sig.equals(staticHookSig)) {
164             return new CodeEmitter(this, v, access, sig, exceptions) {
165                 public boolean isStaticHook() {
166                     return true;
167                 }
168             };
169         } else {
170             return new CodeEmitter(this, v, access, sig, exceptions);
171         }
172     }
173
174     public CodeEmitter begin_static() {
175         return begin_method(Constants.ACC_STATIC, Constants.SIG_STATIC, null);
176     }
177
178     public void declare_field(int access, String JavaDoc name, Type type, Object JavaDoc value) {
179         FieldInfo existing = (FieldInfo)fieldInfo.get(name);
180         FieldInfo info = new FieldInfo(access, name, type, value);
181         if (existing != null) {
182             if (!info.equals(existing)) {
183                 throw new IllegalArgumentException JavaDoc("Field \"" + name + "\" has been declared differently");
184             }
185         } else {
186             fieldInfo.put(name, info);
187             cv.visitField(access, name, type.getDescriptor(), null, value);
188         }
189     }
190
191     // TODO: make public?
192
boolean isFieldDeclared(String JavaDoc name) {
193         return fieldInfo.get(name) != null;
194     }
195
196     FieldInfo getFieldInfo(String JavaDoc name) {
197         FieldInfo field = (FieldInfo)fieldInfo.get(name);
198         if (field == null) {
199             throw new IllegalArgumentException JavaDoc("Field " + name + " is not declared in " + getClassType().getClassName());
200         }
201         return field;
202     }
203     
204     static class FieldInfo {
205         int access;
206         String JavaDoc name;
207         Type type;
208         Object JavaDoc value;
209         
210         public FieldInfo(int access, String JavaDoc name, Type type, Object JavaDoc value) {
211             this.access = access;
212             this.name = name;
213             this.type = type;
214             this.value = value;
215         }
216
217         public boolean equals(Object JavaDoc o) {
218             if (o == null)
219                 return false;
220             if (!(o instanceof FieldInfo))
221                 return false;
222             FieldInfo other = (FieldInfo)o;
223             if (access != other.access ||
224                 !name.equals(other.name) ||
225                 !type.equals(other.type)) {
226                 return false;
227             }
228             if ((value == null) ^ (other.value == null))
229                 return false;
230             if (value != null && !value.equals(other.value))
231                 return false;
232             return true;
233         }
234
235         public int hashCode() {
236             return access ^ name.hashCode() ^ type.hashCode() ^ ((value == null) ? 0 : value.hashCode());
237         }
238     }
239
240     public void visit(int version,
241                       int access,
242                       String JavaDoc name,
243                       String JavaDoc signature,
244                       String JavaDoc superName,
245                       String JavaDoc[] interfaces) {
246         begin_class(version,
247                     access,
248                     name.replace('/', '.'),
249                     TypeUtils.fromInternalName(superName),
250                     TypeUtils.fromInternalNames(interfaces),
251                     null); // TODO
252
}
253     
254     public void visitEnd() {
255         end_class();
256     }
257     
258     public FieldVisitor visitField(int access,
259                                    String JavaDoc name,
260                                    String JavaDoc desc,
261                                    String JavaDoc signature,
262                                    Object JavaDoc value) {
263         declare_field(access, name, Type.getType(desc), value);
264         return null; // TODO
265
}
266     
267     public MethodVisitor visitMethod(int access,
268                                      String JavaDoc name,
269                                      String JavaDoc desc,
270                                      String JavaDoc signature,
271                                      String JavaDoc[] exceptions) {
272         return begin_method(access,
273                             new Signature(name, desc),
274                             TypeUtils.fromInternalNames(exceptions));
275     }
276 }
277
Popular Tags