1 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 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 private ClassNode classNode; 64 private String internalClassName; 65 private String internalBaseClassName; 66 67 68 public DummyClassGenerator( 69 GeneratorContext context, 70 ClassVisitor classVisitor, 71 ClassLoader classLoader, 72 String sourceFile) { 73 super(classLoader); 74 this.context = context; 75 this.cw = classVisitor; 76 this.sourceFile = sourceFile; 77 } 78 79 public void visitClass(ClassNode classNode) { 82 try { 83 this.classNode = classNode; 84 this.internalClassName = BytecodeHelper.getClassInternalName(classNode.getName()); 85 86 88 classNode.setSuperClass(checkValidType(classNode.getSuperClass(), classNode, "Must be a valid base class")); 90 String [] 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 innerClassName = innerClass.getName(); 110 String innerClassInternalName = BytecodeHelper.getClassInternalName(innerClassName); 111 String outerClassName = internalClassName; MethodNode enclosingMethod = innerClass.getEnclosingMethod(); 113 if (enclosingMethod != null) { 114 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 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 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 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, null); 173 } 174 175 178 public void visitProperty(PropertyNode statement) { 179 } 180 181 182 protected String checkValidType(String type, ASTNode node, String message) { 183 if (type!= null && type.length() == 0) 184 return "java.lang.Object"; 185 if (type.endsWith("[]")) { 186 String postfix = "[]"; 187 String 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 postfix = type.substring(idx); 193 String 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 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 resolveClassName(String type) { 208 return classNode.resolveClassName(type); 209 } 210 211 protected static boolean isPrimitiveFieldType(String 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 loadClass(String name) { 219 if (name.equals(this.classNode.getName())) { 220 return Object .class; 221 } 222 223 if (name == null) { 224 return null; 225 } 226 else if (name.length() == 0) { 227 return Object .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 cls = (Class )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 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 |