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.Collections;
29 import java.util.HashMap;
30 import java.util.HashSet;
31 import java.util.List;
32 import java.util.Locale;
33 import java.util.Map;
34 import java.util.Set;
35 import java.util.jar.JarEntry;
36
37 import org.eclipse.jetty.util.Loader;
38 import org.eclipse.jetty.util.log.Log;
39 import org.eclipse.jetty.util.log.Logger;
40 import org.eclipse.jetty.util.resource.Resource;
41 import org.eclipse.jetty.webapp.JarScanner;
42 import org.objectweb.asm.AnnotationVisitor;
43 import org.objectweb.asm.ClassReader;
44 import org.objectweb.asm.FieldVisitor;
45 import org.objectweb.asm.MethodVisitor;
46 import org.objectweb.asm.commons.EmptyVisitor;
47
48
49
50
51
52
53
54 public class AnnotationParser
55 {
56 private static final Logger LOG = Log.getLogger(AnnotationParser.class);
57
58 protected Set<String> _parsedClassNames = new HashSet<String>();
59 protected List<Handler> _handlers = new ArrayList<Handler>();
60
61 public static String normalize (String name)
62 {
63 if (name==null)
64 return null;
65
66 if (name.startsWith("L") && name.endsWith(";"))
67 name = name.substring(1, name.length()-1);
68
69 if (name.endsWith(".class"))
70 name = name.substring(0, name.length()-".class".length());
71
72 return name.replace('/', '.');
73 }
74
75
76
77 public abstract class Value
78 {
79 String _name;
80
81 public Value (String name)
82 {
83 _name = name;
84 }
85
86 public String getName()
87 {
88 return _name;
89 }
90
91 public abstract Object getValue();
92
93 }
94
95
96
97
98 public class SimpleValue extends Value
99 {
100 Object _val;
101
102 public SimpleValue(String name)
103 {
104 super(name);
105 }
106
107 public void setValue(Object val)
108 {
109 _val=val;
110 }
111 public Object getValue()
112 {
113 return _val;
114 }
115
116 public String toString()
117 {
118 return "("+getName()+":"+_val+")";
119 }
120 }
121
122 public class ListValue extends Value
123 {
124 List<Value> _val;
125
126 public ListValue (String name)
127 {
128 super(name);
129 _val = new ArrayList<Value>();
130 }
131
132 public Object getValue()
133 {
134 return _val;
135 }
136
137 public List<Value> getList()
138 {
139 return _val;
140 }
141
142 public void addValue (Value v)
143 {
144 _val.add(v);
145 }
146
147 public int size ()
148 {
149 return _val.size();
150 }
151
152 public String toString()
153 {
154 StringBuffer buff = new StringBuffer();
155 buff.append("(");
156 buff.append(getName());
157 buff.append(":");
158 for (Value n: _val)
159 {
160 buff.append(" "+n.toString());
161 }
162 buff.append(")");
163
164 return buff.toString();
165 }
166 }
167
168
169
170
171
172
173
174
175 public interface Handler
176 {
177
178 }
179
180
181
182
183
184
185
186
187 public interface DiscoverableAnnotationHandler extends Handler
188 {
189
190
191
192
193
194
195
196
197
198
199
200 public void handleClass (String className, int version, int access,
201 String signature, String superName, String[] interfaces,
202 String annotation, List<Value>values);
203
204
205
206
207
208
209
210
211
212
213
214
215 public void handleMethod (String className, String methodName, int access,
216 String desc, String signature,String[] exceptions,
217 String annotation, List<Value>values);
218
219
220
221
222
223
224
225
226
227
228
229
230
231 public void handleField (String className, String fieldName, int access,
232 String fieldType, String signature, Object value,
233 String annotation, List<Value>values);
234
235
236
237
238
239
240
241 public String getAnnotationName();
242 }
243
244
245
246
247
248
249
250
251 public interface ClassHandler extends Handler
252 {
253 public void handle (String className, int version, int access, String signature, String superName, String[] interfaces);
254 }
255
256
257
258
259
260
261
262
263 public interface MethodHandler extends Handler
264 {
265 public void handle (String className, String methodName, int access, String desc, String signature,String[] exceptions);
266 }
267
268
269
270
271
272
273
274 public interface FieldHandler extends Handler
275 {
276 public void handle (String className, String fieldName, int access, String fieldType, String signature, Object value);
277 }
278
279
280
281
282
283
284
285
286 public class MyAnnotationVisitor implements AnnotationVisitor
287 {
288 List<Value> _annotationValues;
289 String _annotationName;
290
291 public MyAnnotationVisitor (String annotationName, List<Value> values)
292 {
293 _annotationValues = values;
294 _annotationName = annotationName;
295 }
296
297 public List<Value> getAnnotationValues()
298 {
299 return _annotationValues;
300 }
301
302
303
304
305
306 public void visit(String aname, Object avalue)
307 {
308 SimpleValue v = new SimpleValue(aname);
309 v.setValue(avalue);
310 _annotationValues.add(v);
311 }
312
313
314
315
316
317 public AnnotationVisitor visitAnnotation(String name, String desc)
318 {
319 String s = normalize(desc);
320 ListValue v = new ListValue(s);
321 _annotationValues.add(v);
322 MyAnnotationVisitor visitor = new MyAnnotationVisitor(s, v.getList());
323 return visitor;
324 }
325
326
327
328
329
330 public AnnotationVisitor visitArray(String name)
331 {
332 ListValue v = new ListValue(name);
333 _annotationValues.add(v);
334 MyAnnotationVisitor visitor = new MyAnnotationVisitor(null, v.getList());
335 return visitor;
336 }
337
338
339
340
341
342 public void visitEnum(String name, String desc, String value)
343 {
344
345 }
346
347 public void visitEnd()
348 {
349 }
350 }
351
352
353
354
355
356
357
358
359
360 public class MyClassVisitor extends EmptyVisitor
361 {
362 String _className;
363 int _access;
364 String _signature;
365 String _superName;
366 String[] _interfaces;
367 int _version;
368
369
370 public void visit (int version,
371 final int access,
372 final String name,
373 final String signature,
374 final String superName,
375 final String[] interfaces)
376 {
377 _className = normalize(name);
378 _access = access;
379 _signature = signature;
380 _superName = superName;
381 _interfaces = interfaces;
382 _version = version;
383
384 _parsedClassNames.add(_className);
385
386 String[] normalizedInterfaces = null;
387 if (interfaces!= null)
388 {
389 normalizedInterfaces = new String[interfaces.length];
390 int i=0;
391 for (String s : interfaces)
392 normalizedInterfaces[i++] = normalize(s);
393 }
394
395 for (Handler h : AnnotationParser.this._handlers)
396 {
397 if (h instanceof ClassHandler)
398 {
399 ((ClassHandler)h).handle(_className, _version, _access, _signature, normalize(_superName), normalizedInterfaces);
400 }
401 }
402 }
403
404 public AnnotationVisitor visitAnnotation (String desc, boolean visible)
405 {
406 MyAnnotationVisitor visitor = new MyAnnotationVisitor(normalize(desc), new ArrayList<Value>())
407 {
408 public void visitEnd()
409 {
410 super.visitEnd();
411
412
413 for (Handler h : AnnotationParser.this._handlers)
414 {
415 if (h instanceof DiscoverableAnnotationHandler)
416 {
417 DiscoverableAnnotationHandler dah = (DiscoverableAnnotationHandler)h;
418 if (_annotationName.equalsIgnoreCase(dah.getAnnotationName()))
419 dah.handleClass(_className, _version, _access, _signature, _superName, _interfaces, _annotationName, _annotationValues);
420 }
421 }
422 }
423 };
424
425 return visitor;
426 }
427
428 public MethodVisitor visitMethod (final int access,
429 final String name,
430 final String methodDesc,
431 final String signature,
432 final String[] exceptions)
433 {
434
435 return new EmptyVisitor ()
436 {
437 public AnnotationVisitor visitAnnotation(String desc, boolean visible)
438 {
439 MyAnnotationVisitor visitor = new MyAnnotationVisitor (normalize(desc), new ArrayList<Value>())
440 {
441 public void visitEnd()
442 {
443 super.visitEnd();
444
445 for (Handler h : AnnotationParser.this._handlers)
446 {
447 if (h instanceof DiscoverableAnnotationHandler)
448 {
449 DiscoverableAnnotationHandler dah = (DiscoverableAnnotationHandler)h;
450 if (_annotationName.equalsIgnoreCase(dah.getAnnotationName()))
451 dah.handleMethod(_className, name, access, methodDesc, signature, exceptions, _annotationName, _annotationValues);
452 }
453 }
454 }
455 };
456
457 return visitor;
458 }
459 };
460 }
461
462 public FieldVisitor visitField (final int access,
463 final String fieldName,
464 final String fieldType,
465 final String signature,
466 final Object value)
467 {
468
469 return new EmptyVisitor ()
470 {
471 public AnnotationVisitor visitAnnotation(String desc, boolean visible)
472 {
473 MyAnnotationVisitor visitor = new MyAnnotationVisitor(normalize(desc), new ArrayList<Value>())
474 {
475 public void visitEnd()
476 {
477 super.visitEnd();
478 for (Handler h : AnnotationParser.this._handlers)
479 {
480 if (h instanceof DiscoverableAnnotationHandler)
481 {
482 DiscoverableAnnotationHandler dah = (DiscoverableAnnotationHandler)h;
483 if (_annotationName.equalsIgnoreCase(dah.getAnnotationName()))
484 dah.handleField(_className, fieldName, access, fieldType, signature, value, _annotationName, _annotationValues);
485 }
486 }
487 }
488 };
489 return visitor;
490 }
491 };
492 }
493 }
494
495
496
497
498
499
500
501
502
503
504 public void registerAnnotationHandler (String annotationName, DiscoverableAnnotationHandler handler)
505 {
506 _handlers.add(handler);
507 }
508
509
510
511
512
513
514
515 public List<DiscoverableAnnotationHandler> getAnnotationHandlers(String annotationName)
516 {
517 List<DiscoverableAnnotationHandler> handlers = new ArrayList<DiscoverableAnnotationHandler>();
518 for (Handler h:_handlers)
519 {
520 if (h instanceof DiscoverableAnnotationHandler)
521 {
522 DiscoverableAnnotationHandler dah = (DiscoverableAnnotationHandler)h;
523 if (annotationName.equals(dah.getAnnotationName()))
524 handlers.add(dah);
525 }
526 }
527
528 return handlers;
529 }
530
531
532
533
534
535 public List<DiscoverableAnnotationHandler> getAnnotationHandlers()
536 {
537 List<DiscoverableAnnotationHandler> allAnnotationHandlers = new ArrayList<DiscoverableAnnotationHandler>();
538 for (Handler h:_handlers)
539 {
540 if (h instanceof DiscoverableAnnotationHandler)
541 allAnnotationHandlers.add((DiscoverableAnnotationHandler)h);
542 }
543 return allAnnotationHandlers;
544 }
545
546
547
548
549
550 public void registerClassHandler (ClassHandler handler)
551 {
552 _handlers.add(handler);
553 }
554
555
556
557
558
559
560
561
562 public void registerHandler(Handler h)
563 {
564 if (h == null)
565 return;
566
567 _handlers.add(h);
568 }
569
570
571
572
573
574
575
576 public void registerHandlers(List<? extends Handler> handlers)
577 {
578 if (handlers == null)
579 return;
580 _handlers.addAll(handlers);
581 }
582
583
584
585
586
587
588
589
590 public boolean deregisterHandler(Handler h)
591 {
592 return _handlers.remove(h);
593 }
594
595
596
597
598
599 public void clearHandlers()
600 {
601 _handlers.clear();
602 }
603
604
605
606
607
608
609
610 public boolean isParsed (String className)
611 {
612 return _parsedClassNames.contains(className);
613 }
614
615
616
617
618
619
620
621
622
623
624 public void parse (String className, ClassNameResolver resolver)
625 throws Exception
626 {
627 if (className == null)
628 return;
629
630 if (!resolver.isExcluded(className))
631 {
632 if (!isParsed(className) || resolver.shouldOverride(className))
633 {
634 className = className.replace('.', '/')+".class";
635 URL resource = Loader.getResource(this.getClass(), className, false);
636 if (resource!= null)
637 {
638 Resource r = Resource.newResource(resource);
639 scanClass(r.getInputStream());
640 }
641 }
642 }
643 }
644
645
646
647
648
649
650
651
652
653
654
655 public void parse (Class clazz, ClassNameResolver resolver, boolean visitSuperClasses)
656 throws Exception
657 {
658 Class cz = clazz;
659 while (cz != null)
660 {
661 if (!resolver.isExcluded(cz.getName()))
662 {
663 if (!isParsed(cz.getName()) || resolver.shouldOverride(cz.getName()))
664 {
665 String nameAsResource = cz.getName().replace('.', '/')+".class";
666 URL resource = Loader.getResource(this.getClass(), nameAsResource, false);
667 if (resource!= null)
668 {
669 Resource r = Resource.newResource(resource);
670 scanClass(r.getInputStream());
671 }
672 }
673 }
674 if (visitSuperClasses)
675 cz = cz.getSuperclass();
676 else
677 cz = null;
678 }
679 }
680
681
682
683
684
685
686
687
688
689
690 public void parse (String[] classNames, ClassNameResolver resolver)
691 throws Exception
692 {
693 if (classNames == null)
694 return;
695
696 parse(Arrays.asList(classNames), resolver);
697 }
698
699
700
701
702
703
704
705
706
707 public void parse (List<String> classNames, ClassNameResolver resolver)
708 throws Exception
709 {
710 for (String s:classNames)
711 {
712 if ((resolver == null) || (!resolver.isExcluded(s) && (!isParsed(s) || resolver.shouldOverride(s))))
713 {
714 s = s.replace('.', '/')+".class";
715 URL resource = Loader.getResource(this.getClass(), s, false);
716 if (resource!= null)
717 {
718 Resource r = Resource.newResource(resource);
719 scanClass(r.getInputStream());
720 }
721 }
722 }
723 }
724
725
726
727
728
729
730
731
732
733 public void parse (Resource dir, ClassNameResolver resolver)
734 throws Exception
735 {
736 if (!dir.isDirectory() || !dir.exists())
737 return;
738
739
740 String[] files=dir.list();
741 for (int f=0;files!=null && f<files.length;f++)
742 {
743 try
744 {
745 Resource res = dir.addPath(files[f]);
746 if (res.isDirectory())
747 parse(res, resolver);
748 String name = res.getName();
749 if (name.endsWith(".class"))
750 {
751 if ((resolver == null)|| (!resolver.isExcluded(name) && (!isParsed(name) || resolver.shouldOverride(name))))
752 {
753 Resource r = Resource.newResource(res.getURL());
754 scanClass(r.getInputStream());
755 }
756
757 }
758 }
759 catch (Exception ex)
760 {
761 LOG.warn(Log.EXCEPTION,ex);
762 }
763 }
764 }
765
766
767
768
769
770
771
772
773
774
775
776
777 public void parse (ClassLoader loader, boolean visitParents, boolean nullInclusive, final ClassNameResolver resolver)
778 throws Exception
779 {
780 if (loader==null)
781 return;
782
783 if (!(loader instanceof URLClassLoader))
784 return;
785
786 JarScanner scanner = new JarScanner()
787 {
788 public void processEntry(URI jarUri, JarEntry entry)
789 {
790 try
791 {
792 String name = entry.getName();
793 if (name.toLowerCase(Locale.ENGLISH).endsWith(".class"))
794 {
795 String shortName = name.replace('/', '.').substring(0,name.length()-6);
796 if ((resolver == null)
797 ||
798 (!resolver.isExcluded(shortName) && (!isParsed(shortName) || resolver.shouldOverride(shortName))))
799 {
800
801 Resource clazz = Resource.newResource("jar:"+jarUri+"!/"+name);
802 scanClass(clazz.getInputStream());
803 }
804 }
805 }
806 catch (Exception e)
807 {
808 LOG.warn("Problem processing jar entry "+entry, e);
809 }
810 }
811
812 };
813
814 scanner.scan(null, loader, nullInclusive, visitParents);
815 }
816
817
818
819
820
821
822
823
824
825 public void parse (URI[] uris, final ClassNameResolver resolver)
826 throws Exception
827 {
828 if (uris==null)
829 return;
830
831 JarScanner scanner = new JarScanner()
832 {
833 public void processEntry(URI jarUri, JarEntry entry)
834 {
835 try
836 {
837 String name = entry.getName();
838 if (name.toLowerCase(Locale.ENGLISH).endsWith(".class"))
839 {
840 String shortName = name.replace('/', '.').substring(0,name.length()-6);
841
842 if ((resolver == null)
843 ||
844 (!resolver.isExcluded(shortName) && (!isParsed(shortName) || resolver.shouldOverride(shortName))))
845 {
846 Resource clazz = Resource.newResource("jar:"+jarUri+"!/"+name);
847 scanClass(clazz.getInputStream());
848
849 }
850 }
851 }
852 catch (Exception e)
853 {
854 LOG.warn("Problem processing jar entry "+entry, e);
855 }
856 }
857
858 };
859 scanner.scan(null, uris, true);
860 }
861
862
863
864
865
866
867
868 public void parse (URI uri, final ClassNameResolver resolver)
869 throws Exception
870 {
871 if (uri == null)
872 return;
873 URI[] uris = {uri};
874 parse(uris, resolver);
875 }
876
877
878
879
880
881
882
883
884
885 protected void scanClass (InputStream is)
886 throws IOException
887 {
888 ClassReader reader = new ClassReader(is);
889 reader.accept(new MyClassVisitor(), ClassReader.SKIP_CODE|ClassReader.SKIP_DEBUG|ClassReader.SKIP_FRAMES);
890 }
891 }
892