KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > aop > annotation > compiler > ByteCodeAnnotationCompiler


1 /*
2   * JBoss, Home of Professional Open Source
3   * Copyright 2005, JBoss Inc., and individual contributors as indicated
4   * by the @authors tag. See the copyright.txt in the distribution for a
5   * full listing of individual contributors.
6   *
7   * This is free software; you can redistribute it and/or modify it
8   * under the terms of the GNU Lesser General Public License as
9   * published by the Free Software Foundation; either version 2.1 of
10   * the License, or (at your option) any later version.
11   *
12   * This software is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   * Lesser General Public License for more details.
16   *
17   * You should have received a copy of the GNU Lesser General Public
18   * License along with this software; if not, write to the Free
19   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21   */

22 package org.jboss.aop.annotation.compiler;
23
24 import java.io.File JavaDoc;
25 import java.io.FileOutputStream JavaDoc;
26 import java.io.FileReader JavaDoc;
27 import java.net.URI JavaDoc;
28 import java.net.URL JavaDoc;
29 import java.net.URLDecoder JavaDoc;
30 import java.util.ArrayList JavaDoc;
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 /**
48  * Convert doclet tags to JBoss AOP annotation XML
49  *
50  * @author <a HREF="mailto:bill@jboss.org">Bill Burke</a>
51  * @version $Revision: 37823 $
52  */

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 JavaDoc[] args) throws Exception JavaDoc
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 JavaDoc f = new File JavaDoc(args[i]).getCanonicalFile();
83          builder.addSource(new FileReader JavaDoc(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 JavaDoc e)
97             {
98                throw new RuntimeException JavaDoc("failed to compile class: " + clazz.getFullyQualifiedName(), e);
99             }
100          }
101       }
102    }
103
104    private CtMethod getJavassistMethod(JavaMethod method, CtClass clazz) throws Exception JavaDoc
105    {
106       CtMethod methods[] = clazz.getDeclaredMethods();
107       ArrayList JavaDoc possible = new ArrayList JavaDoc();
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 JavaDoc("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 JavaDoc("cannot resolve method" + method.toString());
137    }
138
139    private CtConstructor getJavassistConstructor(JavaMethod method, CtClass clazz, boolean isInnerClass) throws Exception JavaDoc
140    {
141       CtConstructor cons[] = clazz.getDeclaredConstructors();
142       ArrayList JavaDoc possible = new ArrayList JavaDoc();
143       for (int i = 0; i < cons.length; i++)
144       {
145          //non-static inner classes get wrapping class as an "invisible" constructor param
146
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 JavaDoc("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 JavaDoc("cannot resolve constructor" + method.toString());
181    }
182
183    private void compileClass(JavaClass clazz) throws Exception JavaDoc
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 its an inner final class then it wont get a
208
//"hidden" param in the constructor.
209
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       //if there are inner classes: fetch them and call compileClass recursive.
237
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 JavaDoc classFile = ctClass.getName().replace('.', '/') + ".class";
246          URL JavaDoc url = Thread.currentThread().getContextClassLoader().getResource(classFile);
247          if (!url.getProtocol().equals("file"))
248          {
249             throw new RuntimeException JavaDoc(".class file must not be in a jar: " + url.toString());
250          }
251          byte[] byteCode = ctClass.toBytecode();
252          String JavaDoc path = URLDecoder.decode(url.getFile(), "UTF-8");
253          File JavaDoc fp = new File JavaDoc(path);
254          FileOutputStream JavaDoc os = new FileOutputStream JavaDoc(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 JavaDoc
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 JavaDoc
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 JavaDoc
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