|
|||||||||||||||||||
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover | |||||||||||||||||||
Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
DummyClassGenerator.java | 0% | 0% | 0% | 0% |
|
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 sourceFile;
|
|
61 |
|
|
62 |
// current class details
|
|
63 |
private ClassNode classNode;
|
|
64 |
private String internalClassName;
|
|
65 |
private String internalBaseClassName;
|
|
66 |
|
|
67 |
|
|
68 | 0 |
public DummyClassGenerator(
|
69 |
GeneratorContext context, |
|
70 |
ClassVisitor classVisitor, |
|
71 |
ClassLoader classLoader, |
|
72 |
String sourceFile) { |
|
73 | 0 |
super(classLoader);
|
74 | 0 |
this.context = context;
|
75 | 0 |
this.cw = classVisitor;
|
76 | 0 |
this.sourceFile = sourceFile;
|
77 |
} |
|
78 |
|
|
79 |
// GroovyClassVisitor interface
|
|
80 |
//-------------------------------------------------------------------------
|
|
81 | 0 |
public void visitClass(ClassNode classNode) { |
82 | 0 |
try {
|
83 | 0 |
this.classNode = classNode;
|
84 | 0 |
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 | 0 |
classNode.setSuperClass(checkValidType(classNode.getSuperClass(), classNode, "Must be a valid base class"));
|
90 | 0 |
String[] interfaces = classNode.getInterfaces(); |
91 | 0 |
for (int i = 0; i < interfaces.length; i++ ) { |
92 | 0 |
interfaces[i] = checkValidType(interfaces[i], classNode, "Must be a valid interface name");
|
93 |
} |
|
94 |
|
|
95 | 0 |
this.internalBaseClassName = BytecodeHelper.getClassInternalName(classNode.getSuperClass());
|
96 |
|
|
97 | 0 |
cw.visit( |
98 |
asmJDKVersion, |
|
99 |
classNode.getModifiers(), |
|
100 |
internalClassName, |
|
101 |
internalBaseClassName, |
|
102 |
BytecodeHelper.getClassInternalNames(classNode.getInterfaces()), |
|
103 |
sourceFile); |
|
104 |
|
|
105 | 0 |
classNode.visitContents(this);
|
106 |
|
|
107 | 0 |
for (Iterator iter = innerClasses.iterator(); iter.hasNext();) {
|
108 | 0 |
ClassNode innerClass = (ClassNode) iter.next(); |
109 | 0 |
String innerClassName = innerClass.getName(); |
110 | 0 |
String innerClassInternalName = BytecodeHelper.getClassInternalName(innerClassName); |
111 | 0 |
String outerClassName = internalClassName; // default for inner classes
|
112 | 0 |
MethodNode enclosingMethod = innerClass.getEnclosingMethod(); |
113 | 0 |
if (enclosingMethod != null) { |
114 |
// local inner classes do not specify the outer class name
|
|
115 | 0 |
outerClassName = null;
|
116 |
} |
|
117 | 0 |
cw.visitInnerClass( |
118 |
innerClassInternalName, |
|
119 |
outerClassName, |
|
120 |
innerClassName, |
|
121 |
innerClass.getModifiers()); |
|
122 |
} |
|
123 | 0 |
cw.visitEnd(); |
124 |
} |
|
125 |
catch (GroovyRuntimeException e) {
|
|
126 | 0 |
e.setModule(classNode.getModule()); |
127 | 0 |
throw e;
|
128 |
} |
|
129 |
} |
|
130 |
|
|
131 | 0 |
public void visitConstructor(ConstructorNode node) { |
132 |
|
|
133 | 0 |
visitParameters(node, node.getParameters()); |
134 |
|
|
135 | 0 |
String methodType = BytecodeHelper.getMethodDescriptor("void", node.getParameters());
|
136 | 0 |
cv = cw.visitMethod(node.getModifiers(), "<init>", methodType, null, null); |
137 | 0 |
cv.visitTypeInsn(NEW, "java/lang/RuntimeException");
|
138 | 0 |
cv.visitInsn(DUP); |
139 | 0 |
cv.visitLdcInsn("not intended for execution");
|
140 | 0 |
cv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/String;)V"); |
141 | 0 |
cv.visitInsn(ATHROW); |
142 | 0 |
cv.visitMaxs(0, 0); |
143 |
} |
|
144 |
|
|
145 | 0 |
public void visitMethod(MethodNode node) { |
146 |
|
|
147 | 0 |
visitParameters(node, node.getParameters()); |
148 | 0 |
node.setReturnType(checkValidType(node.getReturnType(), node, "Must be a valid return type"));
|
149 |
|
|
150 | 0 |
String methodType = BytecodeHelper.getMethodDescriptor(node.getReturnType(), node.getParameters()); |
151 | 0 |
cv = cw.visitMethod(node.getModifiers(), node.getName(), methodType, null, null); |
152 |
|
|
153 | 0 |
cv.visitTypeInsn(NEW, "java/lang/RuntimeException");
|
154 | 0 |
cv.visitInsn(DUP); |
155 | 0 |
cv.visitLdcInsn("not intended for execution");
|
156 | 0 |
cv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/String;)V"); |
157 | 0 |
cv.visitInsn(ATHROW); |
158 |
|
|
159 | 0 |
cv.visitMaxs(0, 0); |
160 |
} |
|
161 |
|
|
162 | 0 |
public void visitField(FieldNode fieldNode) { |
163 |
|
|
164 |
// lets check that the classes are all valid
|
|
165 | 0 |
fieldNode.setType(checkValidType(fieldNode.getType(), fieldNode, "Must be a valid field class for field: " + fieldNode.getName()));
|
166 |
|
|
167 | 0 |
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 | 0 |
public void visitProperty(PropertyNode statement) { |
179 |
} |
|
180 |
|
|
181 |
|
|
182 | 0 |
protected String checkValidType(String type, ASTNode node, String message) {
|
183 | 0 |
if (type!= null && type.length() == 0) |
184 | 0 |
return "java.lang.Object"; |
185 | 0 |
if (type.endsWith("[]")) { |
186 | 0 |
String postfix = "[]";
|
187 | 0 |
String prefix = type.substring(0, type.length() - 2); |
188 | 0 |
return checkValidType(prefix, node, message) + postfix;
|
189 |
} |
|
190 | 0 |
int idx = type.indexOf('$');
|
191 | 0 |
if (idx > 0) {
|
192 | 0 |
String postfix = type.substring(idx); |
193 | 0 |
String prefix = type.substring(0, idx); |
194 | 0 |
return checkValidType(prefix, node, message) + postfix;
|
195 |
} |
|
196 | 0 |
if (BytecodeHelper.isPrimitiveType(type) || "void".equals(type)) { |
197 | 0 |
return type;
|
198 |
} |
|
199 | 0 |
String original = type; |
200 | 0 |
type = resolveClassName(type); |
201 | 0 |
if (type != null) { |
202 | 0 |
return type;
|
203 |
} |
|
204 |
|
|
205 | 0 |
throw new MissingClassException(original, node, message + " for class: " + classNode.getName()); |
206 |
} |
|
207 | 0 |
protected String resolveClassName(String type) {
|
208 | 0 |
return classNode.resolveClassName(type);
|
209 |
} |
|
210 |
|
|
211 | 0 |
protected static boolean isPrimitiveFieldType(String type) { |
212 | 0 |
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 | 0 |
protected Class loadClass(String name) {
|
219 | 0 |
if (name.equals(this.classNode.getName())) { |
220 | 0 |
return Object.class; |
221 |
} |
|
222 |
|
|
223 | 0 |
if (name == null) { |
224 | 0 |
return null; |
225 |
} |
|
226 | 0 |
else if (name.length() == 0) { |
227 | 0 |
return Object.class; |
228 |
} |
|
229 |
|
|
230 | 0 |
else if ("void".equals(name)) { |
231 | 0 |
return void.class; |
232 |
} |
|
233 | 0 |
else if ("boolean".equals(name)) { |
234 | 0 |
return boolean.class; |
235 |
} |
|
236 | 0 |
else if ("byte".equals(name)) { |
237 | 0 |
return byte.class; |
238 |
} |
|
239 | 0 |
else if ("short".equals(name)) { |
240 | 0 |
return short.class; |
241 |
} |
|
242 | 0 |
else if ("char".equals(name)) { |
243 | 0 |
return char.class; |
244 |
} |
|
245 | 0 |
else if ("int".equals(name)) { |
246 | 0 |
return int.class; |
247 |
} |
|
248 | 0 |
else if ("long".equals(name)) { |
249 | 0 |
return long.class; |
250 |
} |
|
251 | 0 |
else if ("float".equals(name)) { |
252 | 0 |
return float.class; |
253 |
} |
|
254 | 0 |
else if ("double".equals(name)) { |
255 | 0 |
return double.class; |
256 |
} |
|
257 |
|
|
258 | 0 |
name = BytecodeHelper.formatNameForClassLoading(name); |
259 |
|
|
260 | 0 |
try {
|
261 | 0 |
Class cls = (Class)classCache.get(name); |
262 | 0 |
if (cls != null) |
263 | 0 |
return cls;
|
264 |
|
|
265 | 0 |
CompileUnit compileUnit = getCompileUnit(); |
266 | 0 |
if (compileUnit != null) { |
267 | 0 |
cls = compileUnit.loadClass(name); |
268 | 0 |
classCache.put(name, cls); |
269 | 0 |
return cls;
|
270 |
} |
|
271 |
else {
|
|
272 | 0 |
throw new ClassGeneratorException("Could not load class: " + name); |
273 |
} |
|
274 |
} |
|
275 |
catch (ClassNotFoundException e) {
|
|
276 | 0 |
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 | 0 |
classCache.put("int", Integer.TYPE);
|
283 | 0 |
classCache.put("byte", Byte.TYPE);
|
284 | 0 |
classCache.put("short", Short.TYPE);
|
285 | 0 |
classCache.put("char", Character.TYPE);
|
286 | 0 |
classCache.put("boolean", Boolean.TYPE);
|
287 | 0 |
classCache.put("long", Long.TYPE);
|
288 | 0 |
classCache.put("double", Double.TYPE);
|
289 | 0 |
classCache.put("float", Float.TYPE);
|
290 |
} |
|
291 | 0 |
protected CompileUnit getCompileUnit() {
|
292 | 0 |
CompileUnit answer = classNode.getCompileUnit(); |
293 | 0 |
if (answer == null) { |
294 | 0 |
answer = context.getCompileUnit(); |
295 |
} |
|
296 | 0 |
return answer;
|
297 |
} |
|
298 |
|
|
299 | 0 |
protected void visitParameters(ASTNode node, Parameter[] parameters) { |
300 | 0 |
for (int i = 0, size = parameters.length; i < size; i++ ) { |
301 | 0 |
visitParameter(node, parameters[i]); |
302 |
} |
|
303 |
} |
|
304 |
|
|
305 | 0 |
protected void visitParameter(ASTNode node, Parameter parameter) { |
306 | 0 |
if (! parameter.isDynamicType()) {
|
307 | 0 |
parameter.setType(checkValidType(parameter.getType(), node, "Must be a valid parameter class"));
|
308 |
} |
|
309 |
} |
|
310 |
|
|
311 |
} |
|
312 |
|
|