1 22 package org.jboss.aop.annotation.compiler; 23 24 import java.io.File ; 25 import java.io.FileOutputStream ; 26 import java.io.FileReader ; 27 import java.net.URI ; 28 import java.net.URL ; 29 import java.net.URLDecoder ; 30 import java.util.ArrayList ; 31 import com.thoughtworks.qdox.JavaDocBuilder; 32 import com.thoughtworks.qdox.model.JavaClass; 33 import com.thoughtworks.qdox.model.JavaField; 34 import com.thoughtworks.qdox.model.JavaMethod; 35 import com.thoughtworks.qdox.model.JavaSource; 36 import javassist.ClassPool; 37 import javassist.CtClass; 38 import javassist.CtConstructor; 39 import javassist.CtField; 40 import javassist.CtMethod; 41 import javassist.LoaderClassPath; 42 import javassist.bytecode.AnnotationsAttribute; 43 import javassist.bytecode.ClassFile; 44 import javassist.bytecode.FieldInfo; 45 import javassist.bytecode.MethodInfo; 46 47 53 public class ByteCodeAnnotationCompiler 54 { 55 ClassPool pool; 56 57 public void usage() 58 { 59 System.err.println("Usage: annotationc <files>+"); 60 } 61 62 public void compile(String [] args) throws Exception 63 { 64 if (args.length == 0) 65 { 66 usage(); 67 System.exit(1); 68 return; 69 } 70 JavaDocBuilder builder = new JavaDocBuilder(new AnnotationDocletTagFactory()); 71 pool = new ClassPool(); 72 pool.appendSystemPath(); 73 pool.appendClassPath(new LoaderClassPath(Thread.currentThread().getContextClassLoader())); 74 for (int i = 0; i < args.length; i++) 75 { 76 if (args[i].equals("-bytecode")) 77 { 78 continue; 79 } 80 if (args[i].equals("-o")) continue; 81 if (args[i].equals("-xml")) continue; 82 File f = new File (args[i]).getCanonicalFile(); 83 builder.addSource(new FileReader (f)); 84 } 85 86 for (int i = 0; i < builder.getSources().length; i++) 87 { 88 JavaSource src = builder.getSources()[i]; 89 for (int j = 0; j < src.getClasses().length; j++) 90 { 91 JavaClass clazz = src.getClasses()[j]; 92 try 93 { 94 compileClass(clazz); 95 } 96 catch (Exception e) 97 { 98 throw new RuntimeException ("failed to compile class: " + clazz.getFullyQualifiedName(), e); 99 } 100 } 101 } 102 } 103 104 private CtMethod getJavassistMethod(JavaMethod method, CtClass clazz) throws Exception 105 { 106 CtMethod methods[] = clazz.getDeclaredMethods(); 107 ArrayList possible = new ArrayList (); 108 for (int i = 0; i < methods.length; i++) 109 { 110 if (methods[i].getName().equals(method.getName())) 111 { 112 if (methods[i].getParameterTypes().length == method.getParameters().length) 113 { 114 possible.add(methods[i]); 115 } 116 } 117 } 118 if (possible.size() == 0) throw new RuntimeException ("cannot resolve method" + method.toString()); 119 if (possible.size() == 1) return (CtMethod) possible.get(0); 120 121 for (int i = 0; i < possible.size(); i++) 122 { 123 CtMethod ctMethod = (CtMethod) possible.get(i); 124 CtClass[] params = ctMethod.getParameterTypes(); 125 boolean bad = false; 126 for (int k = 0; k < params.length; k++) 127 { 128 if (!params[k].getName().equals(method.getParameters()[k].getType().toString())) 129 { 130 bad = true; 131 break; 132 } 133 } 134 if (!bad) return ctMethod; 135 } 136 throw new RuntimeException ("cannot resolve method" + method.toString()); 137 } 138 139 private CtConstructor getJavassistConstructor(JavaMethod method, CtClass clazz, boolean isInnerClass) throws Exception 140 { 141 CtConstructor cons[] = clazz.getDeclaredConstructors(); 142 ArrayList possible = new ArrayList (); 143 for (int i = 0; i < cons.length; i++) 144 { 145 if(isInnerClass) 147 { 148 if (cons[i].getParameterTypes().length == method.getParameters().length+1) 149 { 150 possible.add(cons[i]); 151 } 152 } 153 else 154 { 155 if (cons[i].getParameterTypes().length == method.getParameters().length) 156 { 157 possible.add(cons[i]); 158 } 159 } 160 } 161 162 if (possible.size() == 0) throw new RuntimeException ("cannot resolve constructor" + method.toString()); 163 if (possible.size() == 1) return (CtConstructor) possible.get(0); 164 165 for (int i = 0; i < possible.size(); i++) 166 { 167 CtConstructor ctCon = (CtConstructor) possible.get(i); 168 CtClass[] params = ctCon.getParameterTypes(); 169 boolean bad = false; 170 for (int k = 0; k < params.length; k++) 171 { 172 if (!params[k].getName().equals(method.getParameters()[k].getType().toString())) 173 { 174 bad = true; 175 break; 176 } 177 } 178 if (!bad) return ctCon; 179 } 180 throw new RuntimeException ("cannot resolve constructor" + method.toString()); 181 } 182 183 private void compileClass(JavaClass clazz) throws Exception 184 { 185 CtClass ctClass = pool.get(clazz.getFullyQualifiedName()); 186 boolean modified = false; 187 for (int i = 0; i < clazz.getTags().length; i++) 188 { 189 AnnotationDocletTag tag = (AnnotationDocletTag) clazz.getTags()[i]; 190 if (tag.getAnnotation() == null) continue; 191 modified = true; 192 javassist.bytecode.annotation.Annotation info = AnnotationInfoCreator.createAnnotationInfo(pool, ctClass.getClassFile().getConstPool(), tag.getAnnotation()); 193 AnnotationsAttribute visible = getVisibleAnnotationsAttribute(ctClass); 194 visible.addAnnotation(info); 195 visible.getAnnotations(); 196 } 197 for (int i = 0; i < clazz.getMethods().length; i++) 198 { 199 JavaMethod method = clazz.getMethods()[i]; 200 for (int j = 0; j < method.getTags().length; j++) 201 { 202 AnnotationDocletTag tag = (AnnotationDocletTag) method.getTags()[j]; 203 if (tag.getAnnotation() == null) continue; 204 modified = true; 205 if (method.isConstructor()) 206 { 207 if(clazz.isInner() && !clazz.isStatic()) 210 { 211 compileConstructor(method, tag, ctClass, true); 212 } 213 else 214 { 215 compileConstructor(method, tag, ctClass, false); 216 } 217 } 218 else 219 { 220 compileMethod(method, tag, ctClass); 221 } 222 } 223 } 224 for (int i = 0; i < clazz.getFields().length; i++) 225 { 226 JavaField field = clazz.getFields()[i]; 227 for (int j = 0; j < field.getTags().length; j++) 228 { 229 AnnotationDocletTag tag = (AnnotationDocletTag) field.getTags()[j]; 230 if (tag.getAnnotation() == null) continue; 231 modified = true; 232 compileField(field, tag, ctClass); 233 } 234 } 235 236 for (int i = 0; i < clazz.getInnerClasses().length; i++) 238 { 239 JavaClass innerClass = clazz.getInnerClasses()[i]; 240 compileClass(innerClass); 241 } 242 243 if (modified) 244 { 245 String classFile = ctClass.getName().replace('.', '/') + ".class"; 246 URL url = Thread.currentThread().getContextClassLoader().getResource(classFile); 247 if (!url.getProtocol().equals("file")) 248 { 249 throw new RuntimeException (".class file must not be in a jar: " + url.toString()); 250 } 251 byte[] byteCode = ctClass.toBytecode(); 252 String path = URLDecoder.decode(url.getFile(), "UTF-8"); 253 File fp = new File (path); 254 FileOutputStream os = new FileOutputStream (fp); 255 os.write(byteCode); 256 os.close(); 257 System.out.println("[compiled] " + fp); 258 } 259 260 261 } 262 263 private AnnotationsAttribute getVisibleAnnotationsAttribute(CtClass ctClass) 264 { 265 AnnotationsAttribute visible = (AnnotationsAttribute) ctClass.getClassFile().getAttribute(AnnotationsAttribute.visibleTag); 266 if (visible == null) 267 { 268 ClassFile cf = ctClass.getClassFile(); 269 visible = new AnnotationsAttribute(cf.getConstPool(), AnnotationsAttribute.visibleTag); 270 cf.addAttribute(visible); 271 } 272 return visible; 273 } 274 275 private void compileMethod(JavaMethod method, AnnotationDocletTag tag, CtClass clazz) throws Exception 276 { 277 CtMethod ctMethod = getJavassistMethod(method, clazz); 278 MethodInfo minfo = ctMethod.getMethodInfo(); 279 javassist.bytecode.annotation.Annotation info = AnnotationInfoCreator.createAnnotationInfo(pool, minfo.getConstPool(), tag.getAnnotation()); 280 AnnotationsAttribute visible = (AnnotationsAttribute) minfo.getAttribute(AnnotationsAttribute.visibleTag); 281 if (visible == null) 282 { 283 visible = new AnnotationsAttribute(minfo.getConstPool(), AnnotationsAttribute.visibleTag); 284 minfo.addAttribute(visible); 285 } 286 visible.addAnnotation(info); 287 288 } 289 290 private void compileField(JavaField field, AnnotationDocletTag tag, CtClass clazz) throws Exception 291 { 292 CtField ctField = clazz.getDeclaredField(field.getName()); 293 FieldInfo minfo = ctField.getFieldInfo(); 294 javassist.bytecode.annotation.Annotation info = AnnotationInfoCreator.createAnnotationInfo(pool, minfo.getConstPool(), tag.getAnnotation()); 295 AnnotationsAttribute visible = (AnnotationsAttribute) minfo.getAttribute(AnnotationsAttribute.visibleTag); 296 if (visible == null) 297 { 298 visible = new AnnotationsAttribute(minfo.getConstPool(), AnnotationsAttribute.visibleTag); 299 minfo.addAttribute(visible); 300 } 301 visible.addAnnotation(info); 302 } 303 304 private void compileConstructor(JavaMethod method, AnnotationDocletTag tag, CtClass clazz, boolean isInnerClass) throws Exception 305 { 306 CtConstructor ctMethod = getJavassistConstructor(method, clazz, isInnerClass); 307 MethodInfo minfo = ctMethod.getMethodInfo(); 308 javassist.bytecode.annotation.Annotation info = AnnotationInfoCreator.createAnnotationInfo(pool, minfo.getConstPool(), tag.getAnnotation()); 309 AnnotationsAttribute visible = (AnnotationsAttribute) minfo.getAttribute(AnnotationsAttribute.visibleTag); 310 if (visible == null) 311 { 312 visible = new AnnotationsAttribute(minfo.getConstPool(), AnnotationsAttribute.visibleTag); 313 minfo.addAttribute(visible); 314 } 315 visible.addAnnotation(info); 316 } 317 } 318 | Popular Tags |