|
|||||||||||||||||||
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.1 2004/07/10 03:31:39 bran 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.1 $
|
|
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 |
classNode.getModifiers(), |
|
99 |
internalClassName, |
|
100 |
internalBaseClassName, |
|
101 |
BytecodeHelper.getClassInternalNames(classNode.getInterfaces()), |
|
102 |
sourceFile); |
|
103 |
|
|
104 | 0 |
classNode.visitContents(this);
|
105 |
|
|
106 | 0 |
for (Iterator iter = innerClasses.iterator(); iter.hasNext();) {
|
107 | 0 |
ClassNode innerClass = (ClassNode) iter.next(); |
108 | 0 |
String innerClassName = innerClass.getName(); |
109 | 0 |
String innerClassInternalName = BytecodeHelper.getClassInternalName(innerClassName); |
110 | 0 |
String outerClassName = internalClassName; // default for inner classes
|
111 | 0 |
MethodNode enclosingMethod = innerClass.getEnclosingMethod(); |
112 | 0 |
if (enclosingMethod != null) { |
113 |
// local inner classes do not specify the outer class name
|
|
114 | 0 |
outerClassName = null;
|
115 |
} |
|
116 | 0 |
cw.visitInnerClass( |
117 |
innerClassInternalName, |
|
118 |
outerClassName, |
|
119 |
innerClassName, |
|
120 |
innerClass.getModifiers()); |
|
121 |
} |
|
122 | 0 |
cw.visitEnd(); |
123 |
} |
|
124 |
catch (GroovyRuntimeException e) {
|
|
125 | 0 |
e.setModule(classNode.getModule()); |
126 | 0 |
throw e;
|
127 |
} |
|
128 |
} |
|
129 |
|
|
130 | 0 |
public void visitConstructor(ConstructorNode node) { |
131 |
|
|
132 | 0 |
visitParameters(node, node.getParameters()); |
133 |
|
|
134 | 0 |
String methodType = BytecodeHelper.getMethodDescriptor("void", node.getParameters());
|
135 | 0 |
cv = cw.visitMethod(node.getModifiers(), "<init>", methodType, null, null); |
136 | 0 |
cv.visitTypeInsn(NEW, "java/lang/RuntimeException");
|
137 | 0 |
cv.visitInsn(DUP); |
138 | 0 |
cv.visitLdcInsn("not intended for execution");
|
139 | 0 |
cv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/String;)V"); |
140 | 0 |
cv.visitInsn(ATHROW); |
141 | 0 |
cv.visitMaxs(0, 0); |
142 |
} |
|
143 |
|
|
144 | 0 |
public void visitMethod(MethodNode node) { |
145 |
|
|
146 | 0 |
visitParameters(node, node.getParameters()); |
147 | 0 |
node.setReturnType(checkValidType(node.getReturnType(), node, "Must be a valid return type"));
|
148 |
|
|
149 | 0 |
String methodType = BytecodeHelper.getMethodDescriptor(node.getReturnType(), node.getParameters()); |
150 | 0 |
cv = cw.visitMethod(node.getModifiers(), node.getName(), methodType, null, null); |
151 |
|
|
152 | 0 |
cv.visitTypeInsn(NEW, "java/lang/RuntimeException");
|
153 | 0 |
cv.visitInsn(DUP); |
154 | 0 |
cv.visitLdcInsn("not intended for execution");
|
155 | 0 |
cv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/String;)V"); |
156 | 0 |
cv.visitInsn(ATHROW); |
157 |
|
|
158 | 0 |
cv.visitMaxs(0, 0); |
159 |
} |
|
160 |
|
|
161 | 0 |
public void visitField(FieldNode fieldNode) { |
162 |
|
|
163 |
// lets check that the classes are all valid
|
|
164 | 0 |
fieldNode.setType(checkValidType(fieldNode.getType(), fieldNode, "Must be a valid field class for field: " + fieldNode.getName()));
|
165 |
|
|
166 | 0 |
cw.visitField( |
167 |
fieldNode.getModifiers(), |
|
168 |
fieldNode.getName(), |
|
169 |
BytecodeHelper.getTypeDescription(fieldNode.getType()), |
|
170 |
null, //fieldValue, //br all the sudden that one cannot init the field here. init is done in static initilizer and instace intializer. |
|
171 |
null);
|
|
172 |
} |
|
173 |
|
|
174 |
/**
|
|
175 |
* Creates a getter, setter and field
|
|
176 |
*/
|
|
177 | 0 |
public void visitProperty(PropertyNode statement) { |
178 |
} |
|
179 |
|
|
180 |
|
|
181 | 0 |
protected String checkValidType(String type, ASTNode node, String message) {
|
182 | 0 |
if (type!= null && type.length() == 0) |
183 | 0 |
return "java.lang.Object"; |
184 | 0 |
if (type.endsWith("[]")) { |
185 | 0 |
String postfix = "[]";
|
186 | 0 |
String prefix = type.substring(0, type.length() - 2); |
187 | 0 |
return checkValidType(prefix, node, message) + postfix;
|
188 |
} |
|
189 | 0 |
int idx = type.indexOf('$');
|
190 | 0 |
if (idx > 0) {
|
191 | 0 |
String postfix = type.substring(idx); |
192 | 0 |
String prefix = type.substring(0, idx); |
193 | 0 |
return checkValidType(prefix, node, message) + postfix;
|
194 |
} |
|
195 | 0 |
if (BytecodeHelper.isPrimitiveType(type) || "void".equals(type)) { |
196 | 0 |
return type;
|
197 |
} |
|
198 | 0 |
String original = type; |
199 | 0 |
type = resolveClassName(type); |
200 | 0 |
if (type != null) { |
201 | 0 |
return type;
|
202 |
} |
|
203 |
|
|
204 | 0 |
throw new MissingClassException(original, node, message + " for class: " + classNode.getName()); |
205 |
} |
|
206 | 0 |
protected String resolveClassName(String type) {
|
207 | 0 |
return classNode.resolveClassName(type);
|
208 |
} |
|
209 |
|
|
210 | 0 |
protected static boolean isPrimitiveFieldType(String type) { |
211 | 0 |
return type.equals("java.lang.String") |
212 |
|| type.equals("java.lang.Integer")
|
|
213 |
|| type.equals("java.lang.Double")
|
|
214 |
|| type.equals("java.lang.Long")
|
|
215 |
|| type.equals("java.lang.Float");
|
|
216 |
} |
|
217 | 0 |
protected Class loadClass(String name) {
|
218 | 0 |
if (name.equals(this.classNode.getName())) { |
219 | 0 |
return Object.class; |
220 |
} |
|
221 |
|
|
222 | 0 |
if (name == null) { |
223 | 0 |
return null; |
224 |
} |
|
225 | 0 |
else if (name.length() == 0) { |
226 | 0 |
return Object.class; |
227 |
} |
|
228 |
|
|
229 | 0 |
else if ("void".equals(name)) { |
230 | 0 |
return void.class; |
231 |
} |
|
232 | 0 |
else if ("boolean".equals(name)) { |
233 | 0 |
return boolean.class; |
234 |
} |
|
235 | 0 |
else if ("byte".equals(name)) { |
236 | 0 |
return byte.class; |
237 |
} |
|
238 | 0 |
else if ("short".equals(name)) { |
239 | 0 |
return short.class; |
240 |
} |
|
241 | 0 |
else if ("char".equals(name)) { |
242 | 0 |
return char.class; |
243 |
} |
|
244 | 0 |
else if ("int".equals(name)) { |
245 | 0 |
return int.class; |
246 |
} |
|
247 | 0 |
else if ("long".equals(name)) { |
248 | 0 |
return long.class; |
249 |
} |
|
250 | 0 |
else if ("float".equals(name)) { |
251 | 0 |
return float.class; |
252 |
} |
|
253 | 0 |
else if ("double".equals(name)) { |
254 | 0 |
return double.class; |
255 |
} |
|
256 |
|
|
257 | 0 |
name = BytecodeHelper.formatNameForClassLoading(name); |
258 |
|
|
259 | 0 |
try {
|
260 | 0 |
Class cls = (Class)classCache.get(name); |
261 | 0 |
if (cls != null) |
262 | 0 |
return cls;
|
263 |
|
|
264 | 0 |
CompileUnit compileUnit = getCompileUnit(); |
265 | 0 |
if (compileUnit != null) { |
266 | 0 |
cls = compileUnit.loadClass(name); |
267 | 0 |
classCache.put(name, cls); |
268 | 0 |
return cls;
|
269 |
} |
|
270 |
else {
|
|
271 | 0 |
throw new ClassGeneratorException("Could not load class: " + name); |
272 |
} |
|
273 |
} |
|
274 |
catch (ClassNotFoundException e) {
|
|
275 | 0 |
throw new ClassGeneratorException("Error when compiling class: " + classNode.getName() + ". Reason: could not load class: " + name + " reason: " + e, e); |
276 |
} |
|
277 |
} |
|
278 |
|
|
279 |
Map classCache = new HashMap();
|
|
280 |
{ |
|
281 | 0 |
classCache.put("int", Integer.TYPE);
|
282 | 0 |
classCache.put("byte", Byte.TYPE);
|
283 | 0 |
classCache.put("short", Short.TYPE);
|
284 | 0 |
classCache.put("char", Character.TYPE);
|
285 | 0 |
classCache.put("boolean", Boolean.TYPE);
|
286 | 0 |
classCache.put("long", Long.TYPE);
|
287 | 0 |
classCache.put("double", Double.TYPE);
|
288 | 0 |
classCache.put("float", Float.TYPE);
|
289 |
} |
|
290 | 0 |
protected CompileUnit getCompileUnit() {
|
291 | 0 |
CompileUnit answer = classNode.getCompileUnit(); |
292 | 0 |
if (answer == null) { |
293 | 0 |
answer = context.getCompileUnit(); |
294 |
} |
|
295 | 0 |
return answer;
|
296 |
} |
|
297 |
|
|
298 | 0 |
protected void visitParameters(ASTNode node, Parameter[] parameters) { |
299 | 0 |
for (int i = 0, size = parameters.length; i < size; i++ ) { |
300 | 0 |
visitParameter(node, parameters[i]); |
301 |
} |
|
302 |
} |
|
303 |
|
|
304 | 0 |
protected void visitParameter(ASTNode node, Parameter parameter) { |
305 | 0 |
if (! parameter.isDynamicType()) {
|
306 | 0 |
parameter.setType(checkValidType(parameter.getType(), node, "Must be a valid parameter class"));
|
307 |
} |
|
308 |
} |
|
309 |
|
|
310 |
} |
|
311 |
|
|