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