You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by db...@apache.org on 2006/10/31 03:23:21 UTC

svn commit: r469340 - in /geronimo/xbean/trunk/xbean-finder: ./ src/main/java/org/apache/xbean/finder/ src/test/java/org/acme/bar/ src/test/java/org/acme/foo/ src/test/java/org/apache/xbean/finder/

Author: dblevins
Date: Mon Oct 30 18:23:19 2006
New Revision: 469340

URL: http://svn.apache.org/viewvc?view=rev&rev=469340
Log:
ASM-based class finder

Added:
    geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/
    geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/AnnType.java
    geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Construct.java
    geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Field.java
    geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/FullyAnnotated.java
    geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Get.java
    geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Method.java
    geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Optional.java
    geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Package.java
    geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/ParamA.java
    geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/ParamB.java
    geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Set.java
    geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Type.java
    geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Variable.java
    geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/foo/Deployable.java
    geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/foo/Property.java
    geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/foo/package-info.java
Modified:
    geronimo/xbean/trunk/xbean-finder/pom.xml
    geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/ClassFinder.java
    geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/foo/Green.java
    geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/ClassFinderTest.java

Modified: geronimo/xbean/trunk/xbean-finder/pom.xml
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/pom.xml?view=diff&rev=469340&r1=469339&r2=469340
==============================================================================
--- geronimo/xbean/trunk/xbean-finder/pom.xml (original)
+++ geronimo/xbean/trunk/xbean-finder/pom.xml Mon Oct 30 18:23:19 2006
@@ -54,7 +54,28 @@
             </plugin>
         </plugins>
     </build>
-    
+
+    <dependencies>
+        <dependency>
+           <groupId>asm</groupId>
+           <artifactId>asm</artifactId>
+           <version>2.2.3</version>
+           <scope>provided</scope>
+        </dependency>
+        <dependency>
+           <groupId>asm</groupId>
+           <artifactId>asm-commons</artifactId>
+           <version>2.2.3</version>
+           <scope>provided</scope>
+        </dependency>
+        <dependency>
+           <groupId>asm</groupId>
+           <artifactId>asm-util</artifactId>
+           <version>2.2.3</version>
+           <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
     <!--
     NOTE: Overridding some reports to configure for JDK 1.5
     -->

Modified: geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/ClassFinder.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/ClassFinder.java?view=diff&rev=469340&r1=469339&r2=469340
==============================================================================
--- geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/ClassFinder.java (original)
+++ geronimo/xbean/trunk/xbean-finder/src/main/java/org/apache/xbean/finder/ClassFinder.java Mon Oct 30 18:23:19 2006
@@ -16,31 +16,92 @@
  */
 package org.apache.xbean.finder;
 
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.commons.EmptyVisitor;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
 import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.HashMap;
-import java.util.Collection;
-import java.util.Arrays;
 import java.util.jar.JarEntry;
 import java.util.jar.JarInputStream;
-import java.io.IOException;
-import java.io.File;
-import java.io.InputStream;
 
 /**
+ * ClassFinder searches the classpath of the specified classloader for
+ * packages, classes, constructors, methods, or fields with specific annotations.
+ *
+ * For security reasons ASM is used to find the annotations.  Classes are not
+ * loaded unless they match the requirements of a called findAnnotated* method.
+ * Once loaded, these classes are cached.
+ *
+ * The getClassesNotLoaded() method can be used immediately after any find*
+ * method to get a list of classes which matched the find requirements (i.e.
+ * contained the annotation), but were unable to be loaded.
+ *
+ * @author David Blevins
  * @version $Rev$ $Date$
  */
 public class ClassFinder {
+    private final Map<String, List<Info>> annotated = new HashMap();
+
     private final ClassLoader classLoader;
-    private final List<Class> classes;
     private final List<String> classesNotLoaded = new ArrayList();
 
+    /**
+     * Creates a ClassFinder that will search the urls in the specified classloader
+     * excluding the urls in the classloader's parent.
+     *
+     * To include the parent classloader, use:
+     *
+     *    new ClassFinder(classLoader, false);
+     *
+     * To exclude the parent's parent, use:
+     *
+     *    new ClassFinder(classLoader, classLoader.getParent().getParent());
+     *
+     * @param classLoader
+     * @throws Exception
+     */
     public ClassFinder(ClassLoader classLoader) throws Exception {
-        this(classLoader, excludeParentUrls(classLoader));
+        this(classLoader, true);
+    }
+
+    /**
+     * Creates a ClassFinder that will search the urls in the specified classloader.
+     *
+     * @param classLoader
+     * @param excludeParent
+     * @throws Exception
+     */
+    public ClassFinder(ClassLoader classLoader, boolean excludeParent) throws Exception {
+        this(classLoader, getUrls(classLoader, excludeParent));
+    }
+
+    /**
+     * Creates a ClassFinder that will search the urls in the specified classloader excluding
+     * the urls in the 'exclude' classloader.
+     *
+     * @param classLoader
+     * @param exclude
+     * @throws Exception
+     */
+    public ClassFinder(ClassLoader classLoader, ClassLoader exclude) throws Exception {
+        this(classLoader, getUrls(classLoader, exclude));
     }
 
     public ClassFinder(ClassLoader classLoader, URL url) {
@@ -63,83 +124,175 @@
             }
         }
 
-        classes = new ArrayList();
         for (String className : classNames) {
-            try {
-                Class clazz = classLoader.loadClass(className);
-                classes.add(clazz);
-            } catch (ClassNotFoundException e) {
-                classesNotLoaded.add(className);
-            } catch (NoClassDefFoundError e) {
-                classesNotLoaded.add(className);
-            }
+            readClassDef(className);
         }
+
     }
 
+    /**
+     * Returns a list of classes that could not be loaded in last invoked findAnnotated* method.
+     * <p/>
+     * The list will only contain entries of classes whose byte code matched the requirements
+     * of last invoked find* method, but were unable to be loaded and included in the results.
+     * <p/>
+     * The list returned is unmodifiable and the results of this method will change
+     * after each invocation of a findAnnotated* method.
+     * <p/>
+     * This method is not thread safe.
+     */
     public List<String> getClassesNotLoaded() {
-        return classesNotLoaded;
+        return Collections.unmodifiableList(classesNotLoaded);
+    }
+
+    public List<Package> findAnnotatedPackages(Class<? extends Annotation> annotation) {
+        classesNotLoaded.clear();
+        List<Package> packages = new ArrayList<Package>();
+        List<Info> infos = getAnnotationInfos(annotation.getName());
+        for (Info info : infos) {
+            if (info instanceof PackageInfo) {
+                PackageInfo packageInfo = (PackageInfo) info;
+                try {
+                    Package pkg = packageInfo.get();
+                    // double check via proper reflection
+                    if (pkg.isAnnotationPresent(annotation)) {
+                        packages.add(pkg);
+                    }
+                } catch (ClassNotFoundException e) {
+                    classesNotLoaded.add(packageInfo.getName());
+                }
+            }
+        }
+        return packages;
     }
 
     public List<Class> findAnnotatedClasses(Class<? extends Annotation> annotation) {
-        List<Class> allClasses = getClasses();
+        classesNotLoaded.clear();
         List<Class> classes = new ArrayList<Class>();
-        for (Class clazz : allClasses) {
-            if (clazz.isAnnotationPresent(annotation)) {
-                classes.add(clazz);
+        List<Info> infos = getAnnotationInfos(annotation.getName());
+        for (Info info : infos) {
+            if (info instanceof ClassInfo) {
+                ClassInfo classInfo = (ClassInfo) info;
+                try {
+                    Class clazz = classInfo.get();
+                    // double check via proper reflection
+                    if (clazz.isAnnotationPresent(annotation)) {
+                        classes.add(clazz);
+                    }
+                } catch (ClassNotFoundException e) {
+                    classesNotLoaded.add(classInfo.getName());
+                }
             }
         }
         return classes;
     }
 
-    public Map<Class<? extends Annotation>,List<Class>> mapAnnotatedClasses() {
-        List<Class> allClasses = getClasses();
-        Map<Class<? extends Annotation>,List<Class>> mappedClasses = new HashMap();
-        for (Class clazz : allClasses) {
-            if (Annotation.class.isAssignableFrom(clazz)){
-                continue;
+    public List<Method> findAnnotatedMethods(Class<? extends Annotation> annotation) {
+        classesNotLoaded.clear();
+        List<ClassInfo> seen = new ArrayList<ClassInfo>();
+        List<Method> methods = new ArrayList<Method>();
+        List<Info> infos = getAnnotationInfos(annotation.getName());
+        for (Info info : infos) {
+            if (info instanceof MethodInfo && !info.getName().equals("<init>")) {
+                MethodInfo methodInfo = (MethodInfo) info;
+                ClassInfo classInfo = methodInfo.getDeclaringClass();
+
+                if (seen.contains(classInfo)) continue;
+
+                seen.add(classInfo);
+
+                try {
+                    Class clazz = classInfo.get();
+                    for (Method method : clazz.getDeclaredMethods()) {
+                        if (method.isAnnotationPresent(annotation)) {
+                            methods.add(method);
+                        }
+                    }
+                } catch (ClassNotFoundException e) {
+                    classesNotLoaded.add(classInfo.getName());
+                }
             }
-            for (Annotation annotation : clazz.getAnnotations()) {
-                Class<? extends Annotation> annotationType = annotation.annotationType();
-                List<Class> classes = mappedClasses.get(annotationType);
-                if (classes == null){
-                    classes = new ArrayList();
-                    mappedClasses.put(annotationType, classes);
+        }
+        return methods;
+    }
+
+    public List<Constructor> findAnnotatedConstructors(Class<? extends Annotation> annotation) {
+        classesNotLoaded.clear();
+        List<ClassInfo> seen = new ArrayList<ClassInfo>();
+        List<Constructor> constructors = new ArrayList<Constructor>();
+        List<Info> infos = getAnnotationInfos(annotation.getName());
+        for (Info info : infos) {
+            if (info instanceof MethodInfo && info.getName().equals("<init>")) {
+                MethodInfo methodInfo = (MethodInfo) info;
+                ClassInfo classInfo = methodInfo.getDeclaringClass();
+
+                if (seen.contains(classInfo)) continue;
+
+                seen.add(classInfo);
+
+                try {
+                    Class clazz = classInfo.get();
+                    for (Constructor constructor : clazz.getConstructors()) {
+                        if (constructor.isAnnotationPresent(annotation)) {
+                            constructors.add(constructor);
+                        }
+                    }
+                } catch (ClassNotFoundException e) {
+                    classesNotLoaded.add(classInfo.getName());
                 }
-                classes.add(clazz);
             }
         }
-        return mappedClasses;
+        return constructors;
     }
 
-    public List<Class> findImplementingClasses(Class interfce){
-        List<Class> allClasses = getClasses();
-        List<Class> classes = new ArrayList<Class>();
-        for (Class clazz : allClasses) {
-            if (interfce.isAssignableFrom(clazz) && !interfce.getName().equals(clazz.getName())) {
-                classes.add(clazz);
+    public List<Field> findAnnotatedFields(Class<? extends Annotation> annotation) {
+        classesNotLoaded.clear();
+        List<ClassInfo> seen = new ArrayList<ClassInfo>();
+        List<Field> fields = new ArrayList<Field>();
+        List<Info> infos = getAnnotationInfos(annotation.getName());
+        for (Info info : infos) {
+            if (info instanceof FieldInfo) {
+                FieldInfo fieldInfo = (FieldInfo) info;
+                ClassInfo classInfo = fieldInfo.getDeclaringClass();
+
+                if (seen.contains(classInfo)) continue;
+
+                seen.add(classInfo);
+
+                try {
+                    Class clazz = classInfo.get();
+                    for (Field field : clazz.getDeclaredFields()) {
+                        if (field.isAnnotationPresent(annotation)) {
+                            fields.add(field);
+                        }
+                    }
+                } catch (ClassNotFoundException e) {
+                    classesNotLoaded.add(classInfo.getName());
+                }
             }
         }
-        return classes;
+        return fields;
     }
 
-    public List<Class> getClasses() {
-        return this.classes;
+    private static Collection<URL> getUrls(ClassLoader classLoader, boolean excludeParent) throws IOException {
+        return getUrls(classLoader, excludeParent? classLoader.getParent() : null);
     }
 
-    private static Collection<URL> excludeParentUrls(ClassLoader classLoader) throws IOException {
-        ClassLoader parent = classLoader.getParent();
-        Map<String,URL> parentUrls = toMap(parent.getResources("META-INF"));
-        Map<String,URL> urls = toMap(classLoader.getResources("META-INF"));
+    private static Collection<URL> getUrls(ClassLoader classLoader, ClassLoader excludeParent) throws IOException {
+        Map<String, URL> urls = toMap(classLoader.getResources("META-INF"));
 
-        for (String url : parentUrls.keySet()) {
-            urls.remove(url);
+        if (excludeParent != null) {
+            Map<String, URL> parentUrls = toMap(excludeParent.getResources("META-INF"));
+            for (String url : parentUrls.keySet()) {
+                urls.remove(url);
+            }
         }
 
         return urls.values();
     }
 
-    private static Map<String,URL> toMap(Enumeration<URL> enumeration){
-        Map<String,URL> urls = new HashMap();
+    private static Map<String, URL> toMap(Enumeration<URL> enumeration) {
+        Map<String, URL> urls = new HashMap();
         while (enumeration.hasMoreElements()) {
             URL url = enumeration.nextElement();
             urls.put(url.toExternalForm(), url);
@@ -150,7 +303,7 @@
     private List<String> file(URL location) {
         List<String> classNames = new ArrayList();
         File dir = new File(location.getPath());
-        if (dir.getName().equals("META-INF")){
+        if (dir.getName().equals("META-INF")) {
             dir = dir.getParentFile(); // Scrape "META-INF" off
         }
         if (dir.isDirectory()) {
@@ -162,11 +315,11 @@
     private void scanDir(File dir, List<String> classNames, String packageName) {
         File[] files = dir.listFiles();
         for (File file : files) {
-            if (file.isDirectory()){
+            if (file.isDirectory()) {
                 scanDir(file, classNames, packageName + file.getName() + ".");
             } else if (file.getName().endsWith(".class")) {
                 String name = file.getName();
-                name = name.replaceFirst(".class$","");
+                name = name.replaceFirst(".class$", "");
                 classNames.add(packageName + name);
             }
         }
@@ -175,7 +328,7 @@
     private List<String> jar(URL location) throws IOException {
         List<String> classNames = new ArrayList();
 
-        String jarPath = location.getFile().replaceFirst("./META-INF","");
+        String jarPath = location.getFile().replaceFirst("./META-INF", "");
         URL url = new URL(jarPath);
         InputStream in = url.openStream();
         JarInputStream jarStream = new JarInputStream(in);
@@ -186,11 +339,276 @@
                 continue;
             }
             String className = entry.getName();
-            className = className.replaceFirst(".class$","");
-            className = className.replace('/','.');
+            className = className.replaceFirst(".class$", "");
+            className = className.replace('/', '.');
             classNames.add(className);
         }
 
         return classNames;
+    }
+
+    public static class Annotatable {
+        private final List<AnnotationInfo> annotations = new ArrayList();
+
+        public List<AnnotationInfo> getAnnotations() {
+            return annotations;
+        }
+    }
+
+    public static interface Info {
+        String getName();
+
+        List<AnnotationInfo> getAnnotations();
+    }
+
+    public class PackageInfo extends Annotatable implements Info {
+        private final ClassInfo info;
+
+        public PackageInfo(String name) {
+            info = new ClassInfo(name, null);
+        }
+
+        public String getName() {
+            return info.getName();
+        }
+
+        public Package get() throws ClassNotFoundException {
+            return info.get().getPackage();
+        }
+    }
+
+    public class ClassInfo extends Annotatable implements Info {
+        private final String name;
+        private final List<MethodInfo> methods;
+        private final List<MethodInfo> constructors;
+        private final String superType;
+        private final List<String> interfaces;
+        private final List<FieldInfo> fields;
+        private Class<?> clazz;
+        private ClassNotFoundException notFound;
+
+        public ClassInfo(String name, String superType) {
+            this.name = name;
+            this.superType = superType;
+            this.methods = new ArrayList();
+            this.constructors = new ArrayList();
+            this.interfaces = new ArrayList();
+            this.fields = new ArrayList();
+        }
+
+        public List<MethodInfo> getConstructors() {
+            return constructors;
+        }
+
+        public List<String> getInterfaces() {
+            return interfaces;
+        }
+
+        public List<FieldInfo> getFields() {
+            return fields;
+        }
+
+        public List<MethodInfo> getMethods() {
+            return methods;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public String getSuperType() {
+            return superType;
+        }
+
+        public Class get() throws ClassNotFoundException {
+            if (clazz != null) return clazz;
+            if (notFound != null) throw notFound;
+            try {
+                this.clazz = classLoader.loadClass(name);
+                return clazz;
+            } catch (ClassNotFoundException notFound) {
+                classesNotLoaded.add(name);
+                this.notFound = notFound;
+                throw notFound;
+            }
+        }
+
+        public String toString() {
+            return name;
+        }
+    }
+
+    public class MethodInfo extends Annotatable implements Info {
+        private final ClassInfo declaringClass;
+        private final String returnType;
+        private final String name;
+        private final List<List<AnnotationInfo>> parameterAnnotations;
+
+        public MethodInfo(ClassInfo declarignClass, String name, String returnType) {
+            this.declaringClass = declarignClass;
+            this.name = name;
+            this.returnType = returnType;
+            this.parameterAnnotations = new ArrayList();
+        }
+
+        public List<List<AnnotationInfo>> getParameterAnnotations() {
+            return parameterAnnotations;
+        }
+
+        public List<AnnotationInfo> getParameterAnnotations(int index) {
+            if (index >= parameterAnnotations.size()) {
+                List<AnnotationInfo> annotationInfos = new ArrayList<AnnotationInfo>();
+                parameterAnnotations.add(index, annotationInfos);
+            }
+            return parameterAnnotations.get(index);
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public ClassInfo getDeclaringClass() {
+            return declaringClass;
+        }
+
+        public String getReturnType() {
+            return returnType;
+        }
+
+        public String toString() {
+            return declaringClass + "@" + name;
+        }
+    }
+
+    public class FieldInfo extends Annotatable implements Info {
+        private final String name;
+        private final String type;
+        private final ClassInfo declaringClass;
+
+        public FieldInfo(ClassInfo declaringClass, String name, String type) {
+            this.declaringClass = declaringClass;
+            this.name = name;
+            this.type = type;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public ClassInfo getDeclaringClass() {
+            return declaringClass;
+        }
+
+        public String getType() {
+            return type;
+        }
+
+        public String toString() {
+            return declaringClass + "#" + name;
+        }
+    }
+
+    public class AnnotationInfo extends Annotatable implements Info {
+        private final String name;
+
+        public AnnotationInfo(Class<? extends Annotation> annotation) {
+            this.name = annotation.getName().intern();
+        }
+
+        public AnnotationInfo(String name) {
+            name = name.replaceAll("^L|;$", "");
+            name = name.replace('/', '.');
+            this.name = name.intern();
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public String toString() {
+            return name.toString();
+        }
+    }
+
+    private List<Info> getAnnotationInfos(String name) {
+        List<Info> infos = annotated.get(name);
+        if (infos == null) {
+            infos = new ArrayList();
+            annotated.put(name, infos);
+        }
+        return infos;
+    }
+
+    private void readClassDef(String className) {
+        if (!className.endsWith(".class")) {
+            className = className.replace('.', '/') + ".class";
+        }
+        ClassReader classReader = null;
+        try {
+            URL resource = classLoader.getResource(className);
+            classReader = new ClassReader(resource.openStream());
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+//        classReader.accept(new ASMifierClassVisitor(new PrintWriter(System.out)), true);
+        classReader.accept(new InfoBuildingVisitor(), true);
+    }
+
+    public class InfoBuildingVisitor extends EmptyVisitor {
+        private Info info;
+
+        public InfoBuildingVisitor() {
+        }
+
+        public InfoBuildingVisitor(Info info) {
+            this.info = info;
+        }
+
+        public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+            if (name.endsWith("package-info")) {
+                info = new PackageInfo(javaName(name));
+            } else {
+                ClassInfo classInfo = new ClassInfo(javaName(name), javaName(superName));
+
+                for (String interfce : interfaces) {
+                    classInfo.getInterfaces().add(javaName(interfce));
+                }
+                info = classInfo;
+            }
+        }
+
+        private String javaName(String name) {
+            return (name == null)? null:name.replace('/', '.');
+        }
+
+        public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+            AnnotationInfo annotationInfo = new AnnotationInfo(desc);
+            info.getAnnotations().add(annotationInfo);
+            getAnnotationInfos(annotationInfo.getName()).add(info);
+            return new InfoBuildingVisitor(annotationInfo);
+        }
+
+        public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
+            ClassInfo classInfo = ((ClassInfo) info);
+            FieldInfo fieldInfo = new FieldInfo(classInfo, name, desc);
+            classInfo.getFields().add(fieldInfo);
+            return new InfoBuildingVisitor(fieldInfo);
+        }
+
+        public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+            ClassInfo classInfo = ((ClassInfo) info);
+            MethodInfo methodInfo = new MethodInfo(classInfo, name, desc);
+            classInfo.getMethods().add(methodInfo);
+            return new InfoBuildingVisitor(methodInfo);
+        }
+
+        public AnnotationVisitor visitParameterAnnotation(int param, String desc, boolean visible) {
+            MethodInfo methodInfo = ((MethodInfo) info);
+            List<AnnotationInfo> annotationInfos = methodInfo.getParameterAnnotations(param);
+            AnnotationInfo annotationInfo = new AnnotationInfo(desc);
+            annotationInfos.add(annotationInfo);
+            return new InfoBuildingVisitor(annotationInfo);
+        }
     }
 }

Added: geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/AnnType.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/AnnType.java?view=auto&rev=469340
==============================================================================
--- geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/AnnType.java (added)
+++ geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/AnnType.java Mon Oct 30 18:23:19 2006
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.acme.bar;
+
+/**
+ * @version $Revision$ $Date$
+ */
+@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.ANNOTATION_TYPE})
+@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
+public @interface AnnType {
+}

Added: geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Construct.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Construct.java?view=auto&rev=469340
==============================================================================
--- geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Construct.java (added)
+++ geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Construct.java Mon Oct 30 18:23:19 2006
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.acme.bar;
+
+/**
+ * @version $Revision$ $Date$
+ */
+@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.CONSTRUCTOR})
+@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
+public @interface Construct {
+}

Added: geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Field.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Field.java?view=auto&rev=469340
==============================================================================
--- geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Field.java (added)
+++ geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Field.java Mon Oct 30 18:23:19 2006
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.acme.bar;
+
+/**
+ * @version $Revision$ $Date$
+ */
+@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.FIELD})
+@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
+public @interface Field {
+}

Added: geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/FullyAnnotated.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/FullyAnnotated.java?view=auto&rev=469340
==============================================================================
--- geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/FullyAnnotated.java (added)
+++ geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/FullyAnnotated.java Mon Oct 30 18:23:19 2006
@@ -0,0 +1,111 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.acme.bar;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * @version $Revision$ $Date$
+ */
+@Type public class FullyAnnotated<Cheese extends java.util.Stack,Fun extends java.util.Iterator<java.lang.Exception>,Beeer> {
+    @Field private String field;
+    @Field private char[] characters;
+    @Field private String[] strings;
+    @Field private String[][] moreStrings;
+    @Field private List<String> stringList;
+    @Field private Cheese spam;
+    @Field private Direction direction;
+
+    @Construct public FullyAnnotated(@ParamA String constructorParam, @ParamB @Optional int anInt) {
+        this.field = constructorParam;
+        this.stringList = new ArrayList();
+    }
+
+    @Method public void doIt(int i, boolean b, double d, short s){}
+
+    @Method public void doMore(Cheese cheese, Fun fun){}
+
+    @Type enum Direction {
+        NORTH, SOUTH, EAST, WEST
+    }
+
+    public Direction getDirection() {
+        return direction;
+    }
+
+    public void setDirection(Direction direction) {
+        this.direction = direction;
+    }
+
+    public Cheese getSpam() {
+        return spam;
+    }
+
+    public void setSpam(Cheese spam) {
+        this.spam = spam;
+    }
+
+    public void setSpam(Object spam) {
+        this.spam = (Cheese)spam;
+    }
+
+    @Get @Method public String getField() {
+        @Variable String theField = this.field;
+        return theField;
+    }
+
+    @Set @Method public void setField(@ParamB String methodParam) {
+        this.field = methodParam;
+    }
+
+    @Get @Method public char[] getCharacters() {
+        return characters;
+    }
+
+    @Set @Method public void setCharacters(char[] characters) {
+        this.characters = characters;
+    }
+
+    @Get @Method public String[] getStrings() {
+        return strings;
+    }
+
+    @Set @Method public void setStrings(String[] strings) {
+        this.strings = strings;
+    }
+
+    @Get @Method public String[][] getMoreStrings() {
+        return moreStrings;
+    }
+
+    @Set @Method public void setMoreStrings(@ParamA String[][] moreStrings) {
+        this.moreStrings = moreStrings;
+    }
+
+    @Get @Method public List<String> getStringList() {
+        return stringList;
+    }
+
+    @Set @Method public void setStringList(List<String> stringList) {
+        this.stringList = stringList;
+    }
+
+    @Set @Method public void setStringList(ArrayList stringList) {
+        this.stringList = stringList;
+    }
+}

Added: geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Get.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Get.java?view=auto&rev=469340
==============================================================================
--- geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Get.java (added)
+++ geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Get.java Mon Oct 30 18:23:19 2006
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.acme.bar;
+
+/**
+ * @version $Revision$ $Date$
+ */
+@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.METHOD})
+@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
+public @interface Get {
+}

Added: geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Method.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Method.java?view=auto&rev=469340
==============================================================================
--- geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Method.java (added)
+++ geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Method.java Mon Oct 30 18:23:19 2006
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.acme.bar;
+
+/**
+ * @version $Revision$ $Date$
+ */
+@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.METHOD})
+@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
+public @interface Method {
+}

Added: geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Optional.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Optional.java?view=auto&rev=469340
==============================================================================
--- geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Optional.java (added)
+++ geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Optional.java Mon Oct 30 18:23:19 2006
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.acme.bar;
+
+/**
+ * @version $Revision$ $Date$
+ */
+@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.PARAMETER})
+@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
+public @interface Optional {
+}

Added: geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Package.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Package.java?view=auto&rev=469340
==============================================================================
--- geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Package.java (added)
+++ geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Package.java Mon Oct 30 18:23:19 2006
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.acme.bar;
+
+/**
+ * @version $Revision$ $Date$
+ */
+@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.PACKAGE})
+@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
+public @interface Package {
+}

Added: geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/ParamA.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/ParamA.java?view=auto&rev=469340
==============================================================================
--- geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/ParamA.java (added)
+++ geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/ParamA.java Mon Oct 30 18:23:19 2006
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.acme.bar;
+
+/**
+ * @version $Revision$ $Date$
+ */
+@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.PARAMETER})
+@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
+public @interface ParamA {
+}

Added: geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/ParamB.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/ParamB.java?view=auto&rev=469340
==============================================================================
--- geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/ParamB.java (added)
+++ geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/ParamB.java Mon Oct 30 18:23:19 2006
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.acme.bar;
+
+/**
+ * @version $Revision$ $Date$
+ */
+@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.PARAMETER})
+@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
+public @interface ParamB {
+}

Added: geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Set.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Set.java?view=auto&rev=469340
==============================================================================
--- geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Set.java (added)
+++ geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Set.java Mon Oct 30 18:23:19 2006
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.acme.bar;
+
+/**
+ * @version $Revision$ $Date$
+ */
+@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.METHOD})
+@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
+public @interface Set {
+}

Added: geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Type.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Type.java?view=auto&rev=469340
==============================================================================
--- geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Type.java (added)
+++ geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Type.java Mon Oct 30 18:23:19 2006
@@ -0,0 +1,26 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.acme.bar;
+
+/**
+ * @version $Revision$ $Date$
+ */
+@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.TYPE})
+@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
+@AnnType
+public @interface Type {
+}

Added: geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Variable.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Variable.java?view=auto&rev=469340
==============================================================================
--- geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Variable.java (added)
+++ geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/bar/Variable.java Mon Oct 30 18:23:19 2006
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.acme.bar;
+
+/**
+ * @version $Revision$ $Date$
+ */
+@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.LOCAL_VARIABLE})
+@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
+public @interface Variable {
+}

Added: geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/foo/Deployable.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/foo/Deployable.java?view=auto&rev=469340
==============================================================================
--- geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/foo/Deployable.java (added)
+++ geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/foo/Deployable.java Mon Oct 30 18:23:19 2006
@@ -0,0 +1,15 @@
+/* =====================================================================
+ *
+ * Copyright (c) 2003 David Blevins.  All rights reserved.
+ *
+ * =====================================================================
+ */
+package org.acme.foo;
+
+/**
+ * @version $Revision$ $Date$
+ */
+@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.PACKAGE})
+@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
+public @interface Deployable {
+}

Modified: geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/foo/Green.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/foo/Green.java?view=diff&rev=469340&r1=469339&r2=469340
==============================================================================
--- geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/foo/Green.java (original)
+++ geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/foo/Green.java Mon Oct 30 18:23:19 2006
@@ -11,4 +11,7 @@
  */
 @Color public class Green implements Primary {
     @Color public static class Emerald extends Green {}
+
+    @Property public void myMethod(){
+    }
 }

Added: geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/foo/Property.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/foo/Property.java?view=auto&rev=469340
==============================================================================
--- geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/foo/Property.java (added)
+++ geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/foo/Property.java Mon Oct 30 18:23:19 2006
@@ -0,0 +1,9 @@
+package org.acme.foo;
+
+/**
+ * @version $Revision$ $Date$
+ */
+@java.lang.annotation.Target(value = {java.lang.annotation.ElementType.METHOD})
+@java.lang.annotation.Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
+public @interface Property {
+}

Added: geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/foo/package-info.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/foo/package-info.java?view=auto&rev=469340
==============================================================================
--- geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/foo/package-info.java (added)
+++ geronimo/xbean/trunk/xbean-finder/src/test/java/org/acme/foo/package-info.java Mon Oct 30 18:23:19 2006
@@ -0,0 +1,2 @@
+@Deployable
+package org.acme.foo;
\ No newline at end of file

Modified: geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/ClassFinderTest.java
URL: http://svn.apache.org/viewvc/geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/ClassFinderTest.java?view=diff&rev=469340&r1=469339&r2=469340
==============================================================================
--- geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/ClassFinderTest.java (original)
+++ geronimo/xbean/trunk/xbean-finder/src/test/java/org/apache/xbean/finder/ClassFinderTest.java Mon Oct 30 18:23:19 2006
@@ -17,44 +17,105 @@
 package org.apache.xbean.finder;
 
 import junit.framework.TestCase;
-
-import java.util.List;
-import java.util.Map;
-import java.lang.annotation.Annotation;
-
-import org.acme.foo.Holiday;
+import org.acme.bar.Get;
+import org.acme.bar.ParamA;
+import org.acme.bar.Construct;
+import org.acme.bar.Type;
+import org.acme.bar.AnnType;
+import org.acme.foo.Blue;
 import org.acme.foo.Color;
-import org.acme.foo.Primary;
+import org.acme.foo.Green;
+import org.acme.foo.Halloween;
+import org.acme.foo.Holiday;
+import org.acme.foo.Red;
+import org.acme.foo.Thanksgiving;
+import org.acme.foo.ValentinesDay;
+import org.acme.foo.Deployable;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.util.List;
 
 /**
+ * @author David Blevins
  * @version $Rev$ $Date$
  */
 public class ClassFinderTest extends TestCase {
 
+    public void testFindAnnotatedPackages() throws Exception {
+        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+
+        ClassFinder classFinder = new ClassFinder(classLoader);
+
+        List<Package> packages = classFinder.findAnnotatedPackages(Deployable.class);
+
+        assertNotNull(packages);
+        assertEquals(1, packages.size());
+        assertTrue(packages.contains(Red.class.getPackage()));
+    }
+
     public void testFindAnnotatedClasses() throws Exception {
-        ClassFinder classFinder = new ClassFinder(Thread.currentThread().getContextClassLoader());
-        List<Class> classes = classFinder.findAnnotatedClasses(Holiday.class);
-        assertNotNull("classes", classes);
-        assertEquals("classes.size", 3, classes.size());
+        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+
+        ClassFinder classFinder = new ClassFinder(classLoader);
+
+        Class[] expected = {Halloween.class, Thanksgiving.class, ValentinesDay.class};
+        List<Class> actual = classFinder.findAnnotatedClasses(Holiday.class);
+
+        assertNotNull(actual);
+        assertEquals(expected.length, actual.size());
+        for (Class clazz : expected) {
+            assertTrue(clazz.getName(), actual.contains(clazz));
+        }
+
+        Class[] expected2 = {Blue.class, Blue.Navy.class, Blue.Sky.class, Green.class, Green.Emerald.class, Red.class, Red.CandyApple.class, Red.Pink.class};
+        actual = classFinder.findAnnotatedClasses(Color.class);
+
+        assertNotNull(actual);
+        assertEquals(expected2.length, actual.size());
+        for (Class clazz : expected2) {
+            assertTrue(clazz.getName(), actual.contains(clazz));
+        }
+
+        Class[] expected3 = {Type.class};
+        actual = classFinder.findAnnotatedClasses(AnnType.class);
+
+        assertNotNull(actual);
+        assertEquals(expected3.length, actual.size());
+        for (Class clazz : expected3) {
+            assertTrue(clazz.getName(), actual.contains(clazz));
+        }
     }
 
-    public void testMapAnnotatedClasses() throws Exception {
+    public void testFindAnnotatedMethods() throws Exception {
         ClassFinder classFinder = new ClassFinder(Thread.currentThread().getContextClassLoader());
-        Map<Class<? extends Annotation>, List<Class>> map = classFinder.mapAnnotatedClasses();
-        List<Class> classes = map.get(Holiday.class);
-        assertNotNull("classes", classes);
-        assertEquals("classes.size", 3, classes.size());
-
-        classes = map.get(Color.class);
-        assertNotNull("classes", classes);
-        assertEquals("classes.size", 8, classes.size());
+        List<Method> methods = classFinder.findAnnotatedMethods(Get.class);
+        assertNotNull("methods", methods);
+        assertEquals("methods.size", 5, methods.size());
+
+        // Annotated parameters don't count
+        methods = classFinder.findAnnotatedMethods(ParamA.class);
+        assertNotNull("methods", methods);
+        assertEquals("methods.size", 0, methods.size());
+
+        // Neither do annotated constructors
+        methods = classFinder.findAnnotatedMethods(Construct.class);
+        assertNotNull("methods", methods);
+        assertEquals("methods.size", 0, methods.size());
     }
 
-    public void testFindImplementingClasses() throws Exception {
+    public void testFindAnnotatedConstructors() throws Exception {
         ClassFinder classFinder = new ClassFinder(Thread.currentThread().getContextClassLoader());
-        List<Class> classes = classFinder.findImplementingClasses(Primary.class);
-        assertNotNull("classes", classes);
-        assertEquals("classes.size", 4, classes.size());
+        List<Constructor> constructors = classFinder.findAnnotatedConstructors(Construct.class);
+        assertNotNull("constructors", constructors);
+        assertEquals("constructors.size", 1, constructors.size());
     }
 
+    public void testFindAnnotatedFields() throws Exception {
+        ClassFinder classFinder = new ClassFinder(Thread.currentThread().getContextClassLoader());
+        List<Field> fields = classFinder.findAnnotatedFields(org.acme.bar.Field.class);
+        assertNotNull("fields", fields);
+        assertEquals("fields.size", 7, fields.size());
+    }
 }