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