001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.xbean.finder;
018
019 import org.objectweb.asm.AnnotationVisitor;
020 import org.objectweb.asm.ClassReader;
021 import org.objectweb.asm.FieldVisitor;
022 import org.objectweb.asm.MethodVisitor;
023 import org.objectweb.asm.commons.EmptyVisitor;
024
025 import java.io.File;
026 import java.io.IOException;
027 import java.io.InputStream;
028 import java.lang.annotation.Annotation;
029 import java.lang.reflect.Constructor;
030 import java.lang.reflect.Field;
031 import java.lang.reflect.Method;
032 import java.lang.reflect.AnnotatedElement;
033 import java.net.URL;
034 import java.net.JarURLConnection;
035 import java.net.URLDecoder;
036 import java.util.ArrayList;
037 import java.util.Arrays;
038 import java.util.Collection;
039 import java.util.Collections;
040 import java.util.Enumeration;
041 import java.util.HashMap;
042 import java.util.List;
043 import java.util.Map;
044 import java.util.jar.JarEntry;
045 import java.util.jar.JarInputStream;
046
047 /**
048 * ClassFinder searches the classpath of the specified classloader for
049 * packages, classes, constructors, methods, or fields with specific annotations.
050 *
051 * For security reasons ASM is used to find the annotations. Classes are not
052 * loaded unless they match the requirements of a called findAnnotated* method.
053 * Once loaded, these classes are cached.
054 *
055 * The getClassesNotLoaded() method can be used immediately after any find*
056 * method to get a list of classes which matched the find requirements (i.e.
057 * contained the annotation), but were unable to be loaded.
058 *
059 * @author David Blevins
060 * @version $Rev: 811210 $ $Date: 2009-09-03 20:07:39 -0700 (Thu, 03 Sep 2009) $
061 */
062 public class ClassFinder {
063 private final Map<String, List<Info>> annotated = new HashMap<String, List<Info>>();
064 private final List<ClassInfo> classInfos = new ArrayList<ClassInfo>();
065
066 private final ClassLoader classLoader;
067 private final List<String> classesNotLoaded = new ArrayList<String>();
068 private final int ASM_FLAGS = ClassReader.SKIP_CODE + ClassReader.SKIP_DEBUG + ClassReader.SKIP_FRAMES;
069
070 /**
071 * Creates a ClassFinder that will search the urls in the specified classloader
072 * excluding the urls in the classloader's parent.
073 *
074 * To include the parent classloader, use:
075 *
076 * new ClassFinder(classLoader, false);
077 *
078 * To exclude the parent's parent, use:
079 *
080 * new ClassFinder(classLoader, classLoader.getParent().getParent());
081 *
082 * @param classLoader source of classes to scan
083 * @throws Exception if something goes wrong
084 */
085 public ClassFinder(ClassLoader classLoader) throws Exception {
086 this(classLoader, true);
087 }
088
089 /**
090 * Creates a ClassFinder that will search the urls in the specified classloader.
091 *
092 * @param classLoader source of classes to scan
093 * @param excludeParent Allegedly excludes classes from parent classloader, whatever that might mean
094 * @throws Exception if something goes wrong.
095 */
096 public ClassFinder(ClassLoader classLoader, boolean excludeParent) throws Exception {
097 this(classLoader, getUrls(classLoader, excludeParent));
098 }
099
100 /**
101 * Creates a ClassFinder that will search the urls in the specified classloader excluding
102 * the urls in the 'exclude' classloader.
103 *
104 * @param classLoader source of classes to scan
105 * @param exclude source of classes to exclude from scanning
106 * @throws Exception if something goes wrong
107 */
108 public ClassFinder(ClassLoader classLoader, ClassLoader exclude) throws Exception {
109 this(classLoader, getUrls(classLoader, exclude));
110 }
111
112 public ClassFinder(ClassLoader classLoader, URL url) {
113 this(classLoader, Arrays.asList(url));
114 }
115
116 public ClassFinder(ClassLoader classLoader, Collection<URL> urls) {
117 this.classLoader = classLoader;
118
119 List<String> classNames = new ArrayList<String>();
120 for (URL location : urls) {
121 try {
122 if (location.getProtocol().equals("jar")) {
123 classNames.addAll(jar(location));
124 } else if (location.getProtocol().equals("file")) {
125 try {
126 // See if it's actually a jar
127 URL jarUrl = new URL("jar", "", location.toExternalForm() + "!/");
128 JarURLConnection juc = (JarURLConnection) jarUrl.openConnection();
129 juc.getJarFile();
130 classNames.addAll(jar(jarUrl));
131 } catch (IOException e) {
132 classNames.addAll(file(location));
133 }
134 }
135 } catch (Exception e) {
136 e.printStackTrace();
137 }
138 }
139
140 for (String className : classNames) {
141 readClassDef(className);
142 }
143 }
144
145 public ClassFinder(Class... classes){
146 this(Arrays.asList(classes));
147 }
148
149 public ClassFinder(List<Class> classes){
150 this.classLoader = null;
151 List<Info> infos = new ArrayList<Info>();
152 List<Package> packages = new ArrayList<Package>();
153 for (Class clazz : classes) {
154
155 try {
156 Package aPackage = clazz.getPackage();
157 if (aPackage != null && !packages.contains(aPackage)){
158 infos.add(new PackageInfo(aPackage));
159 packages.add(aPackage);
160 }
161
162 ClassInfo classInfo = new ClassInfo(clazz);
163 infos.add(classInfo);
164 classInfos.add(classInfo);
165 for (Method method : clazz.getDeclaredMethods()) {
166 infos.add(new MethodInfo(classInfo, method));
167 }
168
169 for (Constructor constructor : clazz.getConstructors()) {
170 infos.add(new MethodInfo(classInfo, constructor));
171 }
172
173 for (Field field : clazz.getDeclaredFields()) {
174 infos.add(new FieldInfo(classInfo, field));
175 }
176 } catch (NoClassDefFoundError e) {
177 throw new NoClassDefFoundError("Could not fully load class: " + clazz.getName() + "\n due to:" + e.getMessage() + "\n in classLoader: \n" + clazz.getClassLoader());
178 }
179 }
180
181 for (Info info : infos) {
182 for (AnnotationInfo annotation : info.getAnnotations()) {
183 List<Info> annotationInfos = getAnnotationInfos(annotation.getName());
184 annotationInfos.add(info);
185 }
186 }
187 }
188
189 public boolean isAnnotationPresent(Class<? extends Annotation> annotation) {
190 List<Info> infos = annotated.get(annotation.getName());
191 return infos != null && !infos.isEmpty();
192 }
193
194 /**
195 * Returns a list of classes that could not be loaded in last invoked findAnnotated* method.
196 * <p/>
197 * The list will only contain entries of classes whose byte code matched the requirements
198 * of last invoked find* method, but were unable to be loaded and included in the results.
199 * <p/>
200 * The list returned is unmodifiable. Once obtained, the returned list will be a live view of the
201 * results from the last findAnnotated* method call.
202 * <p/>
203 * This method is not thread safe.
204 * @return an unmodifiable live view of classes that could not be loaded in previous findAnnotated* call.
205 */
206 public List<String> getClassesNotLoaded() {
207 return Collections.unmodifiableList(classesNotLoaded);
208 }
209
210 public List<Package> findAnnotatedPackages(Class<? extends Annotation> annotation) {
211 classesNotLoaded.clear();
212 List<Package> packages = new ArrayList<Package>();
213 List<Info> infos = getAnnotationInfos(annotation.getName());
214 for (Info info : infos) {
215 if (info instanceof PackageInfo) {
216 PackageInfo packageInfo = (PackageInfo) info;
217 try {
218 Package pkg = packageInfo.get();
219 // double check via proper reflection
220 if (pkg.isAnnotationPresent(annotation)) {
221 packages.add(pkg);
222 }
223 } catch (ClassNotFoundException e) {
224 classesNotLoaded.add(packageInfo.getName());
225 }
226 }
227 }
228 return packages;
229 }
230
231 public List<Class> findAnnotatedClasses(Class<? extends Annotation> annotation) {
232 classesNotLoaded.clear();
233 List<Class> classes = new ArrayList<Class>();
234 List<Info> infos = getAnnotationInfos(annotation.getName());
235 for (Info info : infos) {
236 if (info instanceof ClassInfo) {
237 ClassInfo classInfo = (ClassInfo) info;
238 try {
239 Class clazz = classInfo.get();
240 // double check via proper reflection
241 if (clazz.isAnnotationPresent(annotation)) {
242 classes.add(clazz);
243 }
244 } catch (ClassNotFoundException e) {
245 classesNotLoaded.add(classInfo.getName());
246 }
247 }
248 }
249 return classes;
250 }
251
252 /**
253 * Naive implementation - works extremelly slow O(n^3)
254 *
255 * @param annotation
256 * @return list of directly or indirectly (inherited) annotated classes
257 */
258 public List<Class> findInheritedAnnotatedClasses(Class<? extends Annotation> annotation) {
259 classesNotLoaded.clear();
260 List<Class> classes = new ArrayList<Class>();
261 List<Info> infos = getAnnotationInfos(annotation.getName());
262 for (Info info : infos) {
263 try {
264 if(info instanceof ClassInfo){
265 classes.add(((ClassInfo) info).get());
266 }
267 } catch (ClassNotFoundException cnfe) {
268 // TODO: ignored, but a log message would be appropriate
269 }
270 }
271 boolean annClassFound;
272 List<ClassInfo> tempClassInfos = new ArrayList<ClassInfo>(classInfos);
273 do {
274 annClassFound = false;
275 for (int pos = 0; pos < tempClassInfos.size(); pos++) {
276 ClassInfo classInfo = tempClassInfos.get(pos);
277 try {
278 String superType = classInfo.getSuperType();
279 for (Class clazz : classes) {
280 if (superType.equals(clazz.getName())) {
281 classes.add(classInfo.get());
282 tempClassInfos.remove(pos);
283 annClassFound = true;
284 break;
285 }
286 }
287 } catch (ClassNotFoundException e) {
288 classesNotLoaded.add(classInfo.getName());
289 } catch (NoClassDefFoundError e) {
290 classesNotLoaded.add(classInfo.getName());
291 }
292 }
293 } while (annClassFound);
294 return classes;
295 }
296
297 public List<Method> findAnnotatedMethods(Class<? extends Annotation> annotation) {
298 classesNotLoaded.clear();
299 List<ClassInfo> seen = new ArrayList<ClassInfo>();
300 List<Method> methods = new ArrayList<Method>();
301 List<Info> infos = getAnnotationInfos(annotation.getName());
302 for (Info info : infos) {
303 if (info instanceof MethodInfo && !info.getName().equals("<init>")) {
304 MethodInfo methodInfo = (MethodInfo) info;
305 ClassInfo classInfo = methodInfo.getDeclaringClass();
306
307 if (seen.contains(classInfo)) continue;
308
309 seen.add(classInfo);
310
311 try {
312 Class clazz = classInfo.get();
313 for (Method method : clazz.getDeclaredMethods()) {
314 if (method.isAnnotationPresent(annotation)) {
315 methods.add(method);
316 }
317 }
318 } catch (ClassNotFoundException e) {
319 classesNotLoaded.add(classInfo.getName());
320 }
321 }
322 }
323 return methods;
324 }
325
326 public List<Constructor> findAnnotatedConstructors(Class<? extends Annotation> annotation) {
327 classesNotLoaded.clear();
328 List<ClassInfo> seen = new ArrayList<ClassInfo>();
329 List<Constructor> constructors = new ArrayList<Constructor>();
330 List<Info> infos = getAnnotationInfos(annotation.getName());
331 for (Info info : infos) {
332 if (info instanceof MethodInfo && info.getName().equals("<init>")) {
333 MethodInfo methodInfo = (MethodInfo) info;
334 ClassInfo classInfo = methodInfo.getDeclaringClass();
335
336 if (seen.contains(classInfo)) continue;
337
338 seen.add(classInfo);
339
340 try {
341 Class clazz = classInfo.get();
342 for (Constructor constructor : clazz.getConstructors()) {
343 if (constructor.isAnnotationPresent(annotation)) {
344 constructors.add(constructor);
345 }
346 }
347 } catch (ClassNotFoundException e) {
348 classesNotLoaded.add(classInfo.getName());
349 }
350 }
351 }
352 return constructors;
353 }
354
355 public List<Field> findAnnotatedFields(Class<? extends Annotation> annotation) {
356 classesNotLoaded.clear();
357 List<ClassInfo> seen = new ArrayList<ClassInfo>();
358 List<Field> fields = new ArrayList<Field>();
359 List<Info> infos = getAnnotationInfos(annotation.getName());
360 for (Info info : infos) {
361 if (info instanceof FieldInfo) {
362 FieldInfo fieldInfo = (FieldInfo) info;
363 ClassInfo classInfo = fieldInfo.getDeclaringClass();
364
365 if (seen.contains(classInfo)) continue;
366
367 seen.add(classInfo);
368
369 try {
370 Class clazz = classInfo.get();
371 for (Field field : clazz.getDeclaredFields()) {
372 if (field.isAnnotationPresent(annotation)) {
373 fields.add(field);
374 }
375 }
376 } catch (ClassNotFoundException e) {
377 classesNotLoaded.add(classInfo.getName());
378 }
379 }
380 }
381 return fields;
382 }
383
384 public List<Class> findClassesInPackage(String packageName, boolean recursive) {
385 classesNotLoaded.clear();
386 List<Class> classes = new ArrayList<Class>();
387 for (ClassInfo classInfo : classInfos) {
388 try {
389 if (recursive && classInfo.getPackageName().startsWith(packageName)){
390 classes.add(classInfo.get());
391 } else if (classInfo.getPackageName().equals(packageName)){
392 classes.add(classInfo.get());
393 }
394 } catch (ClassNotFoundException e) {
395 classesNotLoaded.add(classInfo.getName());
396 }
397 }
398 return classes;
399 }
400
401 private static Collection<URL> getUrls(ClassLoader classLoader, boolean excludeParent) throws IOException {
402 return getUrls(classLoader, excludeParent? classLoader.getParent() : null);
403 }
404
405 private static Collection<URL> getUrls(ClassLoader classLoader, ClassLoader excludeParent) throws IOException {
406 UrlSet urlSet = new UrlSet(classLoader);
407 if (excludeParent != null){
408 urlSet = urlSet.exclude(excludeParent);
409 }
410 return urlSet.getUrls();
411 }
412
413 private List<String> file(URL location) {
414 List<String> classNames = new ArrayList<String>();
415 File dir = new File(URLDecoder.decode(location.getPath()));
416 if (dir.getName().equals("META-INF")) {
417 dir = dir.getParentFile(); // Scrape "META-INF" off
418 }
419 if (dir.isDirectory()) {
420 scanDir(dir, classNames, "");
421 }
422 return classNames;
423 }
424
425 private void scanDir(File dir, List<String> classNames, String packageName) {
426 File[] files = dir.listFiles();
427 for (File file : files) {
428 if (file.isDirectory()) {
429 scanDir(file, classNames, packageName + file.getName() + ".");
430 } else if (file.getName().endsWith(".class")) {
431 String name = file.getName();
432 name = name.replaceFirst(".class$", "");
433 if (name.contains(".")) continue;
434 classNames.add(packageName + name);
435 }
436 }
437 }
438
439 private List<String> jar(URL location) throws IOException {
440 String jarPath = location.getFile();
441 if (jarPath.indexOf("!") > -1){
442 jarPath = jarPath.substring(0, jarPath.indexOf("!"));
443 }
444 URL url = new URL(jarPath);
445 InputStream in = url.openStream();
446 try {
447 JarInputStream jarStream = new JarInputStream(in);
448 return jar(jarStream);
449 } finally {
450 in.close();
451 }
452 }
453
454 private List<String> jar(JarInputStream jarStream) throws IOException {
455 List<String> classNames = new ArrayList<String>();
456
457 JarEntry entry;
458 while ((entry = jarStream.getNextJarEntry()) != null) {
459 if (entry.isDirectory() || !entry.getName().endsWith(".class")) {
460 continue;
461 }
462 String className = entry.getName();
463 className = className.replaceFirst(".class$", "");
464 if (className.contains(".")) continue;
465 className = className.replace('/', '.');
466 classNames.add(className);
467 }
468
469 return classNames;
470 }
471
472 public class Annotatable {
473 private final List<AnnotationInfo> annotations = new ArrayList<AnnotationInfo>();
474
475 public Annotatable(AnnotatedElement element) {
476 for (Annotation annotation : element.getAnnotations()) {
477 annotations.add(new AnnotationInfo(annotation.annotationType().getName()));
478 }
479 }
480
481 public Annotatable() {
482 }
483
484 public List<AnnotationInfo> getAnnotations() {
485 return annotations;
486 }
487
488 }
489
490 public static interface Info {
491 String getName();
492
493 List<AnnotationInfo> getAnnotations();
494 }
495
496 public class PackageInfo extends Annotatable implements Info {
497 private final String name;
498 private final ClassInfo info;
499 private final Package pkg;
500
501 public PackageInfo(Package pkg){
502 super(pkg);
503 this.pkg = pkg;
504 this.name = pkg.getName();
505 this.info = null;
506 }
507
508 public PackageInfo(String name) {
509 info = new ClassInfo(name, null);
510 this.name = name;
511 this.pkg = null;
512 }
513
514 public String getName() {
515 return name;
516 }
517
518 public Package get() throws ClassNotFoundException {
519 return (pkg != null)?pkg:info.get().getPackage();
520 }
521 }
522
523 public class ClassInfo extends Annotatable implements Info {
524 private final String name;
525 private final List<MethodInfo> methods = new ArrayList<MethodInfo>();
526 private final List<MethodInfo> constructors = new ArrayList<MethodInfo>();
527 private final String superType;
528 private final List<String> interfaces = new ArrayList<String>();
529 private final List<FieldInfo> fields = new ArrayList<FieldInfo>();
530 private Class<?> clazz;
531 private ClassNotFoundException notFound;
532
533 public ClassInfo(Class clazz) {
534 super(clazz);
535 this.clazz = clazz;
536 this.name = clazz.getName();
537 Class superclass = clazz.getSuperclass();
538 this.superType = superclass != null ? superclass.getName(): null;
539 }
540
541 public ClassInfo(String name, String superType) {
542 this.name = name;
543 this.superType = superType;
544 }
545
546 public String getPackageName(){
547 return name.substring(0,name.lastIndexOf("."));
548 }
549
550 public List<MethodInfo> getConstructors() {
551 return constructors;
552 }
553
554 public List<String> getInterfaces() {
555 return interfaces;
556 }
557
558 public List<FieldInfo> getFields() {
559 return fields;
560 }
561
562 public List<MethodInfo> getMethods() {
563 return methods;
564 }
565
566 public String getName() {
567 return name;
568 }
569
570 public String getSuperType() {
571 return superType;
572 }
573
574 public Class get() throws ClassNotFoundException {
575 if (clazz != null) return clazz;
576 if (notFound != null) throw notFound;
577 try {
578 this.clazz = classLoader.loadClass(name);
579 return clazz;
580 } catch (ClassNotFoundException notFound) {
581 classesNotLoaded.add(name);
582 this.notFound = notFound;
583 throw notFound;
584 }
585 }
586
587 public String toString() {
588 return name;
589 }
590 }
591
592 public class MethodInfo extends Annotatable implements Info {
593 private final ClassInfo declaringClass;
594 private final String returnType;
595 private final String name;
596 private final List<List<AnnotationInfo>> parameterAnnotations = new ArrayList<List<AnnotationInfo>>();
597
598 public MethodInfo(ClassInfo info, Constructor constructor){
599 super(constructor);
600 this.declaringClass = info;
601 this.name = "<init>";
602 this.returnType = Void.TYPE.getName();
603 }
604
605 public MethodInfo(ClassInfo info, Method method){
606 super(method);
607 this.declaringClass = info;
608 this.name = method.getName();
609 this.returnType = method.getReturnType().getName();
610 }
611
612 public MethodInfo(ClassInfo declarignClass, String name, String returnType) {
613 this.declaringClass = declarignClass;
614 this.name = name;
615 this.returnType = returnType;
616 }
617
618 public List<List<AnnotationInfo>> getParameterAnnotations() {
619 return parameterAnnotations;
620 }
621
622 public List<AnnotationInfo> getParameterAnnotations(int index) {
623 if (index >= parameterAnnotations.size()) {
624 for (int i = parameterAnnotations.size(); i <= index; i++) {
625 List<AnnotationInfo> annotationInfos = new ArrayList<AnnotationInfo>();
626 parameterAnnotations.add(i, annotationInfos);
627 }
628 }
629 return parameterAnnotations.get(index);
630 }
631
632 public String getName() {
633 return name;
634 }
635
636 public ClassInfo getDeclaringClass() {
637 return declaringClass;
638 }
639
640 public String getReturnType() {
641 return returnType;
642 }
643
644 public String toString() {
645 return declaringClass + "@" + name;
646 }
647 }
648
649 public class FieldInfo extends Annotatable implements Info {
650 private final String name;
651 private final String type;
652 private final ClassInfo declaringClass;
653
654 public FieldInfo(ClassInfo info, Field field){
655 super(field);
656 this.declaringClass = info;
657 this.name = field.getName();
658 this.type = field.getType().getName();
659 }
660
661 public FieldInfo(ClassInfo declaringClass, String name, String type) {
662 this.declaringClass = declaringClass;
663 this.name = name;
664 this.type = type;
665 }
666
667 public String getName() {
668 return name;
669 }
670
671 public ClassInfo getDeclaringClass() {
672 return declaringClass;
673 }
674
675 public String getType() {
676 return type;
677 }
678
679 public String toString() {
680 return declaringClass + "#" + name;
681 }
682 }
683
684 public class AnnotationInfo extends Annotatable implements Info {
685 private final String name;
686
687 public AnnotationInfo(Annotation annotation){
688 this(annotation.getClass().getName());
689 }
690
691 public AnnotationInfo(Class<? extends Annotation> annotation) {
692 this.name = annotation.getName().intern();
693 }
694
695 public AnnotationInfo(String name) {
696 name = name.replaceAll("^L|;$", "");
697 name = name.replace('/', '.');
698 this.name = name.intern();
699 }
700
701 public String getName() {
702 return name;
703 }
704
705 public String toString() {
706 return name;
707 }
708 }
709
710 private List<Info> getAnnotationInfos(String name) {
711 List<Info> infos = annotated.get(name);
712 if (infos == null) {
713 infos = new ArrayList<Info>();
714 annotated.put(name, infos);
715 }
716 return infos;
717 }
718
719 private void readClassDef(String className) {
720 if (!className.endsWith(".class")) {
721 className = className.replace('.', '/') + ".class";
722 }
723 try {
724 URL resource = classLoader.getResource(className);
725 if (resource != null) {
726 InputStream in = resource.openStream();
727 try {
728 ClassReader classReader = new ClassReader(in);
729 classReader.accept(new InfoBuildingVisitor(), ASM_FLAGS);
730 } finally {
731 in.close();
732 }
733 } else {
734 new Exception("Could not load " + className).printStackTrace();
735 }
736 } catch (IOException e) {
737 e.printStackTrace();
738 }
739
740 }
741
742 public class InfoBuildingVisitor extends EmptyVisitor {
743 private Info info;
744
745 public InfoBuildingVisitor() {
746 }
747
748 public InfoBuildingVisitor(Info info) {
749 this.info = info;
750 }
751
752 public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
753 if (name.endsWith("package-info")) {
754 info = new PackageInfo(javaName(name));
755 } else {
756 ClassInfo classInfo = new ClassInfo(javaName(name), javaName(superName));
757
758 for (String interfce : interfaces) {
759 classInfo.getInterfaces().add(javaName(interfce));
760 }
761 info = classInfo;
762 classInfos.add(classInfo);
763 }
764 }
765
766 private String javaName(String name) {
767 return (name == null)? null:name.replace('/', '.');
768 }
769
770 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
771 AnnotationInfo annotationInfo = new AnnotationInfo(desc);
772 info.getAnnotations().add(annotationInfo);
773 getAnnotationInfos(annotationInfo.getName()).add(info);
774 return new InfoBuildingVisitor(annotationInfo);
775 }
776
777 public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
778 ClassInfo classInfo = ((ClassInfo) info);
779 FieldInfo fieldInfo = new FieldInfo(classInfo, name, desc);
780 classInfo.getFields().add(fieldInfo);
781 return new InfoBuildingVisitor(fieldInfo);
782 }
783
784 public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
785 ClassInfo classInfo = ((ClassInfo) info);
786 MethodInfo methodInfo = new MethodInfo(classInfo, name, desc);
787 classInfo.getMethods().add(methodInfo);
788 return new InfoBuildingVisitor(methodInfo);
789 }
790
791 public AnnotationVisitor visitParameterAnnotation(int param, String desc, boolean visible) {
792 MethodInfo methodInfo = ((MethodInfo) info);
793 List<AnnotationInfo> annotationInfos = methodInfo.getParameterAnnotations(param);
794 AnnotationInfo annotationInfo = new AnnotationInfo(desc);
795 annotationInfos.add(annotationInfo);
796 return new InfoBuildingVisitor(annotationInfo);
797 }
798 }
799 }