KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > codehaus > groovy > classgen > DummyClassGenerator


1 /*
2  * $Id: DummyClassGenerator.java,v 1.2 2004/12/14 16:18:14 russel Exp $
3  *
4  * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
5  *
6  * Redistribution and use of this software and associated documentation
7  * ("Software"), with or without modification, are permitted provided that the
8  * following conditions are met: 1. Redistributions of source code must retain
9  * copyright statements and notices. Redistributions must also contain a copy
10  * of this document. 2. Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer in
12  * the documentation and/or other materials provided with the distribution. 3.
13  * The name "groovy" must not be used to endorse or promote products derived
14  * from this Software without prior written permission of The Codehaus. For
15  * written permission, please contact info@codehaus.org. 4. Products derived
16  * from this Software may not be called "groovy" nor may "groovy" appear in
17  * their names without prior written permission of The Codehaus. "groovy" is a
18  * registered trademark of The Codehaus. 5. Due credit should be given to The
19  * Codehaus - http://groovy.codehaus.org/
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
22  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24  * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
25  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31  * DAMAGE.
32  *
33  */

34 package org.codehaus.groovy.classgen;
35
36 import groovy.lang.GroovyRuntimeException;
37 import groovy.lang.MissingClassException;
38 import org.codehaus.groovy.ast.*;
39 import org.objectweb.asm.ClassVisitor;
40 import org.objectweb.asm.CodeVisitor;
41
42 import java.util.*;
43
44 /**
45  * To generate a class that has all the fields and methods, except that fields are not initilized
46  * and methods are empty. It's intended for being used as a place holder during code generation
47  * of reference to the "this" class itself.
48  *
49  * @author <a HREF="mailto:james@coredevelopers.net">James Strachan</a>
50  * @author <a HREF="mailto:b55r@sina.com">Bing Ran</a>
51  *
52  * @version $Revision: 1.2 $
53  */

54 public class DummyClassGenerator extends ClassGenerator {
55
56     private ClassVisitor cw;
57     private CodeVisitor cv;
58     private GeneratorContext context;
59
60     private String JavaDoc sourceFile;
61
62     // current class details
63
private ClassNode classNode;
64     private String JavaDoc internalClassName;
65     private String JavaDoc internalBaseClassName;
66
67
68     public DummyClassGenerator(
69         GeneratorContext context,
70         ClassVisitor classVisitor,
71         ClassLoader JavaDoc classLoader,
72         String JavaDoc sourceFile) {
73         super(classLoader);
74         this.context = context;
75         this.cw = classVisitor;
76         this.sourceFile = sourceFile;
77     }
78
79     // GroovyClassVisitor interface
80
//-------------------------------------------------------------------------
81
public void visitClass(ClassNode classNode) {
82         try {
83             this.classNode = classNode;
84             this.internalClassName = BytecodeHelper.getClassInternalName(classNode.getName());
85
86             //System.out.println("Generating class: " + classNode.getName());
87

88             // lets check that the classes are all valid
89
classNode.setSuperClass(checkValidType(classNode.getSuperClass(), classNode, "Must be a valid base class"));
90             String JavaDoc[] interfaces = classNode.getInterfaces();
91             for (int i = 0; i < interfaces.length; i++ ) {
92                 interfaces[i] = checkValidType(interfaces[i], classNode, "Must be a valid interface name");
93             }
94
95             this.internalBaseClassName = BytecodeHelper.getClassInternalName(classNode.getSuperClass());
96
97             cw.visit(
98                 asmJDKVersion,
99                 classNode.getModifiers(),
100                 internalClassName,
101                 internalBaseClassName,
102                 BytecodeHelper.getClassInternalNames(classNode.getInterfaces()),
103                 sourceFile);
104
105             classNode.visitContents(this);
106
107             for (Iterator iter = innerClasses.iterator(); iter.hasNext();) {
108                 ClassNode innerClass = (ClassNode) iter.next();
109                 String JavaDoc innerClassName = innerClass.getName();
110                 String JavaDoc innerClassInternalName = BytecodeHelper.getClassInternalName(innerClassName);
111                 String JavaDoc outerClassName = internalClassName; // default for inner classes
112
MethodNode enclosingMethod = innerClass.getEnclosingMethod();
113                 if (enclosingMethod != null) {
114                     // local inner classes do not specify the outer class name
115
outerClassName = null;
116                 }
117                 cw.visitInnerClass(
118                     innerClassInternalName,
119                     outerClassName,
120                     innerClassName,
121                     innerClass.getModifiers());
122             }
123             cw.visitEnd();
124         }
125         catch (GroovyRuntimeException e) {
126             e.setModule(classNode.getModule());
127             throw e;
128         }
129     }
130
131     public void visitConstructor(ConstructorNode node) {
132
133         visitParameters(node, node.getParameters());
134
135         String JavaDoc methodType = BytecodeHelper.getMethodDescriptor("void", node.getParameters());
136         cv = cw.visitMethod(node.getModifiers(), "<init>", methodType, null, null);
137         cv.visitTypeInsn(NEW, "java/lang/RuntimeException");
138         cv.visitInsn(DUP);
139         cv.visitLdcInsn("not intended for execution");
140         cv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/String;)V");
141         cv.visitInsn(ATHROW);
142         cv.visitMaxs(0, 0);
143     }
144
145     public void visitMethod(MethodNode node) {
146
147         visitParameters(node, node.getParameters());
148         node.setReturnType(checkValidType(node.getReturnType(), node, "Must be a valid return type"));
149
150         String JavaDoc methodType = BytecodeHelper.getMethodDescriptor(node.getReturnType(), node.getParameters());
151         cv = cw.visitMethod(node.getModifiers(), node.getName(), methodType, null, null);
152
153         cv.visitTypeInsn(NEW, "java/lang/RuntimeException");
154         cv.visitInsn(DUP);
155         cv.visitLdcInsn("not intended for execution");
156         cv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/String;)V");
157         cv.visitInsn(ATHROW);
158
159         cv.visitMaxs(0, 0);
160     }
161
162     public void visitField(FieldNode fieldNode) {
163
164         // lets check that the classes are all valid
165
fieldNode.setType(checkValidType(fieldNode.getType(), fieldNode, "Must be a valid field class for field: " + fieldNode.getName()));
166
167         cw.visitField(
168             fieldNode.getModifiers(),
169             fieldNode.getName(),
170             BytecodeHelper.getTypeDescription(fieldNode.getType()),
171             null, //fieldValue, //br all the sudden that one cannot init the field here. init is done in static initilizer and instace intializer.
172
null);
173     }
174
175     /**
176      * Creates a getter, setter and field
177      */

178     public void visitProperty(PropertyNode statement) {
179     }
180
181
182     protected String JavaDoc checkValidType(String JavaDoc type, ASTNode node, String JavaDoc message) {
183         if (type!= null && type.length() == 0)
184             return "java.lang.Object";
185         if (type.endsWith("[]")) {
186             String JavaDoc postfix = "[]";
187             String JavaDoc prefix = type.substring(0, type.length() - 2);
188             return checkValidType(prefix, node, message) + postfix;
189         }
190         int idx = type.indexOf('$');
191         if (idx > 0) {
192             String JavaDoc postfix = type.substring(idx);
193             String JavaDoc prefix = type.substring(0, idx);
194             return checkValidType(prefix, node, message) + postfix;
195         }
196         if (BytecodeHelper.isPrimitiveType(type) || "void".equals(type)) {
197             return type;
198         }
199         String JavaDoc original = type;
200         type = resolveClassName(type);
201         if (type != null) {
202             return type;
203         }
204
205         throw new MissingClassException(original, node, message + " for class: " + classNode.getName());
206     }
207     protected String JavaDoc resolveClassName(String JavaDoc type) {
208         return classNode.resolveClassName(type);
209     }
210
211     protected static boolean isPrimitiveFieldType(String JavaDoc type) {
212         return type.equals("java.lang.String")
213             || type.equals("java.lang.Integer")
214             || type.equals("java.lang.Double")
215             || type.equals("java.lang.Long")
216             || type.equals("java.lang.Float");
217     }
218     protected Class JavaDoc loadClass(String JavaDoc name) {
219         if (name.equals(this.classNode.getName())) {
220             return Object JavaDoc.class;
221         }
222
223         if (name == null) {
224             return null;
225         }
226         else if (name.length() == 0) {
227             return Object JavaDoc.class;
228         }
229
230         else if ("void".equals(name)) {
231             return void.class;
232         }
233         else if ("boolean".equals(name)) {
234             return boolean.class;
235         }
236         else if ("byte".equals(name)) {
237             return byte.class;
238         }
239         else if ("short".equals(name)) {
240             return short.class;
241         }
242         else if ("char".equals(name)) {
243             return char.class;
244         }
245         else if ("int".equals(name)) {
246             return int.class;
247         }
248         else if ("long".equals(name)) {
249             return long.class;
250         }
251         else if ("float".equals(name)) {
252             return float.class;
253         }
254         else if ("double".equals(name)) {
255             return double.class;
256         }
257
258         name = BytecodeHelper.formatNameForClassLoading(name);
259
260         try {
261             Class JavaDoc cls = (Class JavaDoc)classCache.get(name);
262             if (cls != null)
263                 return cls;
264
265             CompileUnit compileUnit = getCompileUnit();
266             if (compileUnit != null) {
267                 cls = compileUnit.loadClass(name);
268                 classCache.put(name, cls);
269                 return cls;
270             }
271             else {
272                 throw new ClassGeneratorException("Could not load class: " + name);
273             }
274         }
275         catch (ClassNotFoundException JavaDoc e) {
276             throw new ClassGeneratorException("Error when compiling class: " + classNode.getName() + ". Reason: could not load class: " + name + " reason: " + e, e);
277         }
278     }
279
280     Map classCache = new HashMap();
281     {
282         classCache.put("int", Integer.TYPE);
283         classCache.put("byte", Byte.TYPE);
284         classCache.put("short", Short.TYPE);
285         classCache.put("char", Character.TYPE);
286         classCache.put("boolean", Boolean.TYPE);
287         classCache.put("long", Long.TYPE);
288         classCache.put("double", Double.TYPE);
289         classCache.put("float", Float.TYPE);
290     }
291     protected CompileUnit getCompileUnit() {
292         CompileUnit answer = classNode.getCompileUnit();
293         if (answer == null) {
294             answer = context.getCompileUnit();
295         }
296         return answer;
297     }
298
299     protected void visitParameters(ASTNode node, Parameter[] parameters) {
300         for (int i = 0, size = parameters.length; i < size; i++ ) {
301             visitParameter(node, parameters[i]);
302         }
303     }
304
305     protected void visitParameter(ASTNode node, Parameter parameter) {
306         if (! parameter.isDynamicType()) {
307             parameter.setType(checkValidType(parameter.getType(), node, "Must be a valid parameter class"));
308         }
309     }
310
311 }
312
Popular Tags