1
2
3
4
5
6
7
8
9
10
11
12
13 package org.eclipse.jetty.annotations;
14
15 import java.io.IOException;
16 import java.io.InputStream;
17 import java.net.URI;
18 import java.net.URL;
19 import java.net.URLClassLoader;
20 import java.util.ArrayList;
21 import java.util.Arrays;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.jar.JarEntry;
28
29 import org.eclipse.jetty.util.Loader;
30 import org.eclipse.jetty.util.log.Log;
31 import org.eclipse.jetty.util.resource.Resource;
32 import org.eclipse.jetty.webapp.JarScanner;
33 import org.objectweb.asm.AnnotationVisitor;
34 import org.objectweb.asm.ClassReader;
35 import org.objectweb.asm.FieldVisitor;
36 import org.objectweb.asm.MethodVisitor;
37 import org.objectweb.asm.commons.EmptyVisitor;
38
39
40
41
42
43
44
45 public class AnnotationParser
46 {
47 protected List<String> _parsedClassNames = new ArrayList<String>();
48 protected Map<String, List<DiscoverableAnnotationHandler>> _annotationHandlers = new HashMap<String, List<DiscoverableAnnotationHandler>>();
49 protected List<ClassHandler> _classHandlers = new ArrayList<ClassHandler>();
50 protected List<MethodHandler> _methodHandlers = new ArrayList<MethodHandler>();
51 protected List<FieldHandler> _fieldHandlers = new ArrayList<FieldHandler>();
52
53 public static String normalize (String name)
54 {
55 if (name==null)
56 return null;
57
58 if (name.startsWith("L") && name.endsWith(";"))
59 name = name.substring(1, name.length()-1);
60
61 if (name.endsWith(".class"))
62 name = name.substring(0, name.length()-".class".length());
63
64 return name.replace('/', '.');
65 }
66
67
68
69 public abstract class Value
70 {
71 String _name;
72
73 public Value (String name)
74 {
75 _name = name;
76 }
77
78 public String getName()
79 {
80 return _name;
81 }
82
83 public abstract Object getValue();
84
85 }
86
87
88
89
90 public class SimpleValue extends Value
91 {
92 Object _val;
93
94 public SimpleValue(String name)
95 {
96 super(name);
97 }
98
99 public void setValue(Object val)
100 {
101 _val=val;
102 }
103 public Object getValue()
104 {
105 return _val;
106 }
107
108 public String toString()
109 {
110 return "("+getName()+":"+_val+")";
111 }
112 }
113
114 public class ListValue extends Value
115 {
116 List<Value> _val;
117
118 public ListValue (String name)
119 {
120 super(name);
121 _val = new ArrayList<Value>();
122 }
123
124 public Object getValue()
125 {
126 return _val;
127 }
128
129 public List<Value> getList()
130 {
131 return _val;
132 }
133
134 public void addValue (Value v)
135 {
136 _val.add(v);
137 }
138
139 public int size ()
140 {
141 return _val.size();
142 }
143
144 public String toString()
145 {
146 StringBuffer buff = new StringBuffer();
147 buff.append("(");
148 buff.append(getName());
149 buff.append(":");
150 for (Value n: _val)
151 {
152 buff.append(" "+n.toString());
153 }
154 buff.append(")");
155
156 return buff.toString();
157 }
158 }
159
160
161
162 public interface DiscoverableAnnotationHandler
163 {
164 public void handleClass (String className, int version, int access,
165 String signature, String superName, String[] interfaces,
166 String annotation, List<Value>values);
167
168 public void handleMethod (String className, String methodName, int access,
169 String desc, String signature,String[] exceptions,
170 String annotation, List<Value>values);
171
172 public void handleField (String className, String fieldName, int access,
173 String fieldType, String signature, Object value,
174 String annotation, List<Value>values);
175 }
176
177
178 public interface ClassHandler
179 {
180 public void handle (String className, int version, int access, String signature, String superName, String[] interfaces);
181 }
182
183 public interface MethodHandler
184 {
185 public void handle (String className, String methodName, int access, String desc, String signature,String[] exceptions);
186 }
187
188 public interface FieldHandler
189 {
190 public void handle (String className, String fieldName, int access, String fieldType, String signature, Object value);
191 }
192
193 public class MyAnnotationVisitor implements AnnotationVisitor
194 {
195 List<Value> _annotationValues;
196 String _annotationName;
197
198 public MyAnnotationVisitor (String annotationName, List<Value> values)
199 {
200 _annotationValues = values;
201 _annotationName = annotationName;
202 }
203
204 public List<Value> getAnnotationValues()
205 {
206 return _annotationValues;
207 }
208
209
210
211
212
213 public void visit(String aname, Object avalue)
214 {
215 SimpleValue v = new SimpleValue(aname);
216 v.setValue(avalue);
217 _annotationValues.add(v);
218 }
219
220
221
222
223
224 public AnnotationVisitor visitAnnotation(String name, String desc)
225 {
226 String s = normalize(desc);
227 ListValue v = new ListValue(s);
228 _annotationValues.add(v);
229 MyAnnotationVisitor visitor = new MyAnnotationVisitor(s, v.getList());
230 return visitor;
231 }
232
233
234
235
236
237 public AnnotationVisitor visitArray(String name)
238 {
239 ListValue v = new ListValue(name);
240 _annotationValues.add(v);
241 MyAnnotationVisitor visitor = new MyAnnotationVisitor(null, v.getList());
242 return visitor;
243 }
244
245
246
247
248
249 public void visitEnum(String name, String desc, String value)
250 {
251
252 }
253
254 public void visitEnd()
255 {
256 }
257 }
258
259
260
261
262
263
264
265
266
267 public class MyClassVisitor extends EmptyVisitor
268 {
269 String _className;
270 int _access;
271 String _signature;
272 String _superName;
273 String[] _interfaces;
274 int _version;
275
276
277 public void visit (int version,
278 final int access,
279 final String name,
280 final String signature,
281 final String superName,
282 final String[] interfaces)
283 {
284 _className = normalize(name);
285 _access = access;
286 _signature = signature;
287 _superName = superName;
288 _interfaces = interfaces;
289 _version = version;
290
291 _parsedClassNames.add(_className);
292
293 String[] normalizedInterfaces = null;
294 if (interfaces!= null)
295 {
296 normalizedInterfaces = new String[interfaces.length];
297 int i=0;
298 for (String s : interfaces)
299 normalizedInterfaces[i++] = normalize(s);
300 }
301
302 for (ClassHandler h : AnnotationParser.this._classHandlers)
303 {
304 h.handle(_className, _version, _access, _signature, normalize(_superName), normalizedInterfaces);
305 }
306 }
307
308 public AnnotationVisitor visitAnnotation (String desc, boolean visible)
309 {
310 MyAnnotationVisitor visitor = new MyAnnotationVisitor(normalize(desc), new ArrayList<Value>())
311 {
312 public void visitEnd()
313 {
314 super.visitEnd();
315
316
317 List<DiscoverableAnnotationHandler> handlers = AnnotationParser.this._annotationHandlers.get(_annotationName);
318 if (handlers != null)
319 {
320 for (DiscoverableAnnotationHandler h:handlers)
321 {
322 h.handleClass(_className, _version, _access, _signature, _superName, _interfaces, _annotationName, _annotationValues);
323 }
324 }
325 }
326 };
327
328 return visitor;
329 }
330
331 public MethodVisitor visitMethod (final int access,
332 final String name,
333 final String methodDesc,
334 final String signature,
335 final String[] exceptions)
336 {
337
338 return new EmptyVisitor ()
339 {
340 public AnnotationVisitor visitAnnotation(String desc, boolean visible)
341 {
342 MyAnnotationVisitor visitor = new MyAnnotationVisitor (normalize(desc), new ArrayList<Value>())
343 {
344 public void visitEnd()
345 {
346 super.visitEnd();
347
348 List<DiscoverableAnnotationHandler> handlers = AnnotationParser.this._annotationHandlers.get(_annotationName);
349 if (handlers != null)
350 {
351 for (DiscoverableAnnotationHandler h:handlers)
352 {
353 h.handleMethod(_className, name, access, methodDesc, signature, exceptions, _annotationName, _annotationValues);
354 }
355 }
356 }
357 };
358
359 return visitor;
360 }
361 };
362 }
363
364 public FieldVisitor visitField (final int access,
365 final String fieldName,
366 final String fieldType,
367 final String signature,
368 final Object value)
369 {
370
371 return new EmptyVisitor ()
372 {
373 public AnnotationVisitor visitAnnotation(String desc, boolean visible)
374 {
375 MyAnnotationVisitor visitor = new MyAnnotationVisitor(normalize(desc), new ArrayList<Value>())
376 {
377 public void visitEnd()
378 {
379 super.visitEnd();
380 List<DiscoverableAnnotationHandler> handlers = AnnotationParser.this._annotationHandlers.get(_annotationName);
381 if (handlers != null)
382 {
383 for (DiscoverableAnnotationHandler h:handlers)
384 {
385 h.handleField(_className, fieldName, access, fieldType, signature, value, _annotationName, _annotationValues);
386 }
387 }
388 }
389 };
390 return visitor;
391 }
392 };
393 }
394 }
395
396
397
398
399
400
401
402
403
404 public void registerAnnotationHandler (String annotationName, DiscoverableAnnotationHandler handler)
405 {
406 List<DiscoverableAnnotationHandler> handlers = _annotationHandlers.get(annotationName);
407 if (handlers == null)
408 {
409 handlers = new ArrayList<DiscoverableAnnotationHandler>();
410 _annotationHandlers.put(annotationName, handlers);
411 }
412 handlers.add(handler);
413 }
414
415 public List<DiscoverableAnnotationHandler> getAnnotationHandlers(String annotationName)
416 {
417 List<DiscoverableAnnotationHandler> handlers = _annotationHandlers.get(annotationName);
418 if (handlers == null)
419 return Collections.emptyList();
420 return new ArrayList<DiscoverableAnnotationHandler>();
421 }
422
423 public List<DiscoverableAnnotationHandler> getAnnotationHandlers()
424 {
425 List<DiscoverableAnnotationHandler> allHandlers = new ArrayList<DiscoverableAnnotationHandler>();
426 for (List<DiscoverableAnnotationHandler> list:_annotationHandlers.values())
427 allHandlers.addAll(list);
428 return allHandlers;
429 }
430
431 public void registerClassHandler (ClassHandler handler)
432 {
433 _classHandlers.add(handler);
434 }
435
436 public boolean isParsed (String className)
437 {
438 return _parsedClassNames.contains(className);
439 }
440
441 public void parse (String className, ClassNameResolver resolver)
442 throws Exception
443 {
444 if (className == null)
445 return;
446
447 if (!resolver.isExcluded(className))
448 {
449 if (!isParsed(className) || resolver.shouldOverride(className))
450 {
451 className = className.replace('.', '/')+".class";
452 URL resource = Loader.getResource(this.getClass(), className, false);
453 if (resource!= null)
454 scanClass(resource.openStream());
455 }
456 }
457 }
458
459 public void parse (Class clazz, ClassNameResolver resolver, boolean visitSuperClasses)
460 throws Exception
461 {
462 Class cz = clazz;
463 while (cz != null)
464 {
465 if (!resolver.isExcluded(cz.getName()))
466 {
467 if (!isParsed(cz.getName()) || resolver.shouldOverride(cz.getName()))
468 {
469 String nameAsResource = cz.getName().replace('.', '/')+".class";
470 URL resource = Loader.getResource(this.getClass(), nameAsResource, false);
471 if (resource!= null)
472 scanClass(resource.openStream());
473 }
474 }
475 if (visitSuperClasses)
476 cz = cz.getSuperclass();
477 else
478 cz = null;
479 }
480 }
481
482 public void parse (String[] classNames, ClassNameResolver resolver)
483 throws Exception
484 {
485 if (classNames == null)
486 return;
487
488 parse(Arrays.asList(classNames), resolver);
489 }
490
491 public void parse (List<String> classNames, ClassNameResolver resolver)
492 throws Exception
493 {
494 for (String s:classNames)
495 {
496 if ((resolver == null) || (!resolver.isExcluded(s) && (!isParsed(s) || resolver.shouldOverride(s))))
497 {
498 s = s.replace('.', '/')+".class";
499 URL resource = Loader.getResource(this.getClass(), s, false);
500 if (resource!= null)
501 scanClass(resource.openStream());
502 }
503 }
504 }
505
506 public void parse (Resource dir, ClassNameResolver resolver)
507 throws Exception
508 {
509 if (!dir.isDirectory() || !dir.exists())
510 return;
511
512
513 String[] files=dir.list();
514 for (int f=0;files!=null && f<files.length;f++)
515 {
516 try
517 {
518 Resource res = dir.addPath(files[f]);
519 if (res.isDirectory())
520 parse(res, resolver);
521 String name = res.getName();
522 if (name.endsWith(".class"))
523 {
524 if ((resolver == null)|| (!resolver.isExcluded(name) && (!isParsed(name) || resolver.shouldOverride(name))))
525 scanClass(res.getURL().openStream());
526
527 }
528 }
529 catch (Exception ex)
530 {
531 Log.warn(Log.EXCEPTION,ex);
532 }
533 }
534 }
535
536
537
538
539
540
541
542
543
544
545
546 public void parse (ClassLoader loader, boolean visitParents, boolean nullInclusive, final ClassNameResolver resolver)
547 throws Exception
548 {
549 if (loader==null)
550 return;
551
552 if (!(loader instanceof URLClassLoader))
553 return;
554
555 JarScanner scanner = new JarScanner()
556 {
557 public void processEntry(URI jarUri, JarEntry entry)
558 {
559 try
560 {
561 String name = entry.getName();
562 if (name.toLowerCase().endsWith(".class"))
563 {
564 String shortName = name.replace('/', '.').substring(0,name.length()-6);
565 if ((resolver == null)
566 ||
567 (!resolver.isExcluded(shortName) && (!isParsed(shortName) || resolver.shouldOverride(shortName))))
568 {
569
570 Resource clazz = Resource.newResource("jar:"+jarUri+"!/"+name);
571 scanClass(clazz.getInputStream());
572 }
573 }
574 }
575 catch (Exception e)
576 {
577 Log.warn("Problem processing jar entry "+entry, e);
578 }
579 }
580
581 };
582
583 scanner.scan(null, loader, nullInclusive, visitParents);
584 }
585
586
587
588
589
590
591
592
593 public void parse (URI[] uris, final ClassNameResolver resolver)
594 throws Exception
595 {
596 if (uris==null)
597 return;
598
599 JarScanner scanner = new JarScanner()
600 {
601 public void processEntry(URI jarUri, JarEntry entry)
602 {
603 try
604 {
605 String name = entry.getName();
606 if (name.toLowerCase().endsWith(".class"))
607 {
608 String shortName = name.replace('/', '.').substring(0,name.length()-6);
609
610 if ((resolver == null)
611 ||
612 (!resolver.isExcluded(shortName) && (!isParsed(shortName) || resolver.shouldOverride(shortName))))
613 {
614 Resource clazz = Resource.newResource("jar:"+jarUri+"!/"+name);
615 scanClass(clazz.getInputStream());
616
617 }
618 }
619 }
620 catch (Exception e)
621 {
622 Log.warn("Problem processing jar entry "+entry, e);
623 }
624 }
625
626 };
627 scanner.scan(null, uris, true);
628 }
629
630 public void parse (URI uri, final ClassNameResolver resolver)
631 throws Exception
632 {
633 if (uri == null)
634 return;
635 URI[] uris = {uri};
636 parse(uris, resolver);
637 }
638
639 private void scanClass (InputStream is)
640 throws IOException
641 {
642 ClassReader reader = new ClassReader(is);
643 reader.accept(new MyClassVisitor(), ClassReader.SKIP_CODE|ClassReader.SKIP_DEBUG|ClassReader.SKIP_FRAMES);
644 }
645 }