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