struts-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From lukaszlen...@apache.org
Subject [13/50] [abbrv] struts git commit: Extracts interface with default implementation
Date Wed, 31 Dec 2014 17:17:35 GMT
Extracts interface with default implementation


Project: http://git-wip-us.apache.org/repos/asf/struts/repo
Commit: http://git-wip-us.apache.org/repos/asf/struts/commit/3ce21ac4
Tree: http://git-wip-us.apache.org/repos/asf/struts/tree/3ce21ac4
Diff: http://git-wip-us.apache.org/repos/asf/struts/diff/3ce21ac4

Branch: refs/heads/master
Commit: 3ce21ac4832742241663a671163f40cf12083f99
Parents: 6471eec
Author: Lukasz Lenart <lukaszlenart@apache.org>
Authored: Sat Dec 20 21:45:30 2014 +0100
Committer: Lukasz Lenart <lukaszlenart@apache.org>
Committed: Sat Dec 20 21:45:30 2014 +0100

----------------------------------------------------------------------
 .../xwork2/util/finder/ClassFinder.java         | 640 ++-----------------
 .../xwork2/util/finder/DefaultClassFinder.java  | 609 ++++++++++++++++++
 2 files changed, 648 insertions(+), 601 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/struts/blob/3ce21ac4/xwork-core/src/main/java/com/opensymphony/xwork2/util/finder/ClassFinder.java
----------------------------------------------------------------------
diff --git a/xwork-core/src/main/java/com/opensymphony/xwork2/util/finder/ClassFinder.java b/xwork-core/src/main/java/com/opensymphony/xwork2/util/finder/ClassFinder.java
index f337eb9..aed9981 100644
--- a/xwork-core/src/main/java/com/opensymphony/xwork2/util/finder/ClassFinder.java
+++ b/xwork-core/src/main/java/com/opensymphony/xwork2/util/finder/ClassFinder.java
@@ -1,452 +1,68 @@
-/*
- * Copyright 2002-2003,2009 The Apache Software Foundation.
- * 
- * Licensed 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 com.opensymphony.xwork2.util.finder;
 
-import com.opensymphony.xwork2.ActionContext;
-import com.opensymphony.xwork2.FileManager;
-import com.opensymphony.xwork2.FileManagerFactory;
-import com.opensymphony.xwork2.XWorkException;
-import com.opensymphony.xwork2.util.logging.Logger;
-import com.opensymphony.xwork2.util.logging.LoggerFactory;
-import org.apache.commons.lang3.StringUtils;
-import org.objectweb.asm.AnnotationVisitor;
-import org.objectweb.asm.ClassReader;
-import org.objectweb.asm.FieldVisitor;
-import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.ClassVisitor;
-import org.objectweb.asm.Opcodes;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.AnnotatedElement;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
-import java.net.JarURLConnection;
-import java.net.URL;
-import java.net.URLDecoder;
 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.LinkedHashMap;
 import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.jar.JarEntry;
-import java.util.jar.JarInputStream;
-
-/**
- * ClassFinder searches the classpath of the specified ClassLoaderInterface 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 static final Logger LOG = LoggerFactory.getLogger(ClassFinder.class);
-
-    private final Map<String, List<Info>> annotated = new HashMap<String, List<Info>>();
-    private final Map<String, ClassInfo> classInfos = new LinkedHashMap<String, ClassInfo>();
-
-    private final List<String> classesNotLoaded = new ArrayList<String>();
-
-    private boolean extractBaseInterfaces;
-    private ClassLoaderInterface classLoaderInterface;
-    private FileManager fileManager;
-
-    public ClassFinder(ClassLoaderInterface classLoaderInterface, Collection<URL> urls, boolean extractBaseInterfaces, Set<String> protocols, Test<String> classNameFilter) {
-        this.classLoaderInterface = classLoaderInterface;
-        this.extractBaseInterfaces = extractBaseInterfaces;
-        this.fileManager = ActionContext.getContext().getInstance(FileManagerFactory.class).getFileManager();
-
-        List<String> classNames = new ArrayList<String>();
-        for (URL location : urls) {
-            try {
-                if (protocols.contains(location.getProtocol())) {
-                    classNames.addAll(jar(location));
-                } else if ("file".equals(location.getProtocol())) {
-                    try {
-                        // See if it's actually a jar
-                        URL jarUrl = new URL("jar", "", location.toExternalForm() + "!/");
-                        JarURLConnection juc = (JarURLConnection) jarUrl.openConnection();
-                        juc.getJarFile();
-                        classNames.addAll(jar(jarUrl));
-                    } catch (IOException e) {
-                        classNames.addAll(file(location));
-                    }
-                }
-            } catch (Exception e) {
-                if (LOG.isErrorEnabled())
-                    LOG.error("Unable to read URL [#0]", e, location.toExternalForm());
-            }
-        }
 
-        for (String className : classNames) {
-            try {
-                if (classNameFilter.test(className))
-                    readClassDef(className);
-            } catch (Throwable e) {
-                if (LOG.isErrorEnabled())
-                    LOG.error("Unable to read class [#0]", e, className);
-            }
-        }
-    }
+public interface ClassFinder {
 
-    public ClassFinder(Class... classes){
-        this(Arrays.asList(classes));
-    }
+    boolean isAnnotationPresent(Class<? extends Annotation> annotation);
 
-    public ClassFinder(List<Class> classes){
-        this.classLoaderInterface = null;
-        List<Info> infos = new ArrayList<Info>();
-        List<Package> packages = new ArrayList<Package>();
-        for (Class clazz : classes) {
+    List<String> getClassesNotLoaded();
 
-            Package aPackage = clazz.getPackage();
-            if (aPackage != null && !packages.contains(aPackage)){
-                infos.add(new PackageInfo(aPackage));
-                packages.add(aPackage);
-            }
+    List<Package> findAnnotatedPackages(Class<? extends Annotation> annotation);
 
-            ClassInfo classInfo = new ClassInfo(clazz);
-            infos.add(classInfo);
-            classInfos.put(classInfo.getName(), classInfo);
-            for (Method method : clazz.getDeclaredMethods()) {
-                infos.add(new MethodInfo(classInfo, method));
-            }
+    List<Class> findAnnotatedClasses(Class<? extends Annotation> annotation);
 
-            for (Constructor constructor : clazz.getConstructors()) {
-                infos.add(new MethodInfo(classInfo, constructor));
-            }
+    List<Method> findAnnotatedMethods(Class<? extends Annotation> annotation);
 
-            for (Field field : clazz.getDeclaredFields()) {
-                infos.add(new FieldInfo(classInfo, field));
-            }
-        }
+    List<Constructor> findAnnotatedConstructors(Class<? extends Annotation> annotation);
 
-        for (Info info : infos) {
-            for (AnnotationInfo annotation : info.getAnnotations()) {
-                List<Info> annotationInfos = getAnnotationInfos(annotation.getName());
-                annotationInfos.add(info);
-            }
-        }
-    }
+    List<Field> findAnnotatedFields(Class<? extends Annotation> annotation);
 
-    public boolean isAnnotationPresent(Class<? extends Annotation> annotation) {
-        List<Info> infos = annotated.get(annotation.getName());
-        return infos != null && !infos.isEmpty();
-    }
+    List<Class> findClassesInPackage(String packageName, boolean recursive);
 
-    /**
-     * 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.  Once obtained, the returned list will be a live view of the
-     * results from the last findAnnotated* method call.
-     * <p/>
-     * This method is not thread safe.
-     * @return an unmodifiable live view of classes that could not be loaded in previous findAnnotated* call.
-     */
-    public List<String> getClassesNotLoaded() {
-        return Collections.unmodifiableList(classesNotLoaded);
-    }
+    List<Class> findClasses(Test<ClassInfo> test);
 
-    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;
-    }
+    List<Class> findClasses();
 
-    public List<Class> findAnnotatedClasses(Class<? extends Annotation> annotation) {
-        classesNotLoaded.clear();
-        List<Class> classes = new ArrayList<Class>();
-        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 (Throwable e) {
-                    if (LOG.isErrorEnabled())
-                        LOG.error("Error loading class [#0]", e, classInfo.getName());
-                    classesNotLoaded.add(classInfo.getName());
-                }
-            }
-        }
-        return classes;
-    }
-
-    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 && !"<init>".equals(info.getName())) {
-                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 (Throwable e) {
-                    if (LOG.isErrorEnabled())
-                        LOG.error("Error loading class [#0]", e, classInfo.getName());
-                    classesNotLoaded.add(classInfo.getName());
-                }
-            }
-        }
-        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 && "<init>".equals(info.getName())) {
-                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 (Throwable e) {
-                    if (LOG.isErrorEnabled())
-                        LOG.error("Error loading class [#0]", e, classInfo.getName());
-                    classesNotLoaded.add(classInfo.getName());
-                }
-            }
-        }
-        return constructors;
-    }
+    ClassLoaderInterface getClassLoaderInterface();
 
-    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 (Throwable e) {
-                    if (LOG.isErrorEnabled())
-                        LOG.error("Error loading class [#0]", e, classInfo.getName());
-                    classesNotLoaded.add(classInfo.getName());
-                }
-            }
-        }
-        return fields;
-    }
+    public static interface Info {
+        String getName();
 
-    public List<Class> findClassesInPackage(String packageName, boolean recursive) {
-        classesNotLoaded.clear();
-        List<Class> classes = new ArrayList<Class>();
-        for (ClassInfo classInfo : classInfos.values()) {
-            try {
-                if (recursive && classInfo.getPackageName().startsWith(packageName)){
-                    classes.add(classInfo.get());
-                } else if (classInfo.getPackageName().equals(packageName)){
-                    classes.add(classInfo.get());
-                }
-            } catch (Throwable e) {
-                if (LOG.isErrorEnabled())
-                    LOG.error("Error loading class [#0]", e, classInfo.getName());
-                classesNotLoaded.add(classInfo.getName());
-            }
-        }
-        return classes;
+        List<AnnotationInfo> getAnnotations();
     }
 
-    public List<Class> findClasses(Test<ClassInfo> test) {
-        classesNotLoaded.clear();
-        List<Class> classes = new ArrayList<Class>();
-        for (ClassInfo classInfo : classInfos.values()) {
-            try {
-                if (test.test(classInfo)) {
-                    classes.add(classInfo.get());
-                }
-            } catch (Throwable e) {
-                if (LOG.isErrorEnabled())
-                    LOG.error("Error loading class [#0]", e, classInfo.getName());
-                classesNotLoaded.add(classInfo.getName());
-            }
-        }
-        return classes;
-    }
+    public class AnnotationInfo extends Annotatable implements Info {
+        private final String name;
 
-    public List<Class> findClasses() {
-        classesNotLoaded.clear();
-        List<Class> classes = new ArrayList<Class>();
-        for (ClassInfo classInfo : classInfos.values()) {
-            try {
-                classes.add(classInfo.get());
-            } catch (Throwable e) {
-                if (LOG.isErrorEnabled())
-                    LOG.error("Error loading class [#0]", e, classInfo.getName());
-                classesNotLoaded.add(classInfo.getName());
-            }
+        public AnnotationInfo(Annotation annotation){
+            this(annotation.getClass().getName());
         }
-        return classes;
-    }
 
-    private static List<URL> getURLs(ClassLoaderInterface classLoader, String[] dirNames) {
-        List<URL> urls = new ArrayList<URL>();
-        for (String dirName : dirNames) {
-            try {
-                Enumeration<URL> classLoaderURLs = classLoader.getResources(dirName);
-                while (classLoaderURLs.hasMoreElements()) {
-                    URL url = classLoaderURLs.nextElement();
-                    urls.add(url);
-                }
-            } catch (IOException ioe) {
-                if (LOG.isErrorEnabled())
-                    LOG.error("Could not read driectory [#0]", ioe, dirName);
-            }
+        public AnnotationInfo(Class<? extends Annotation> annotation) {
+            this.name = annotation.getName().intern();
         }
 
-        return urls;
-    }
-
-    private List<String> file(URL location) {
-        List<String> classNames = new ArrayList<String>();
-        File dir = new File(URLDecoder.decode(location.getPath()));
-        if ("META-INF".equals(dir.getName())) {
-            dir = dir.getParentFile(); // Scrape "META-INF" off
-        }
-        if (dir.isDirectory()) {
-            scanDir(dir, classNames, "");
+        public AnnotationInfo(String name) {
+            name = name.replaceAll("^L|;$", "");
+            name = name.replace('/', '.');
+            this.name = name.intern();
         }
-        return classNames;
-    }
 
-    private void scanDir(File dir, List<String> classNames, String packageName) {
-        File[] files = dir.listFiles();
-        for (File file : files) {
-            if (file.isDirectory()) {
-                scanDir(file, classNames, packageName + file.getName() + ".");
-            } else if (file.getName().endsWith(".class")) {
-                String name = file.getName();
-                name = name.replaceFirst(".class$", "");
-                // Classes packaged in an exploded .war (e.g. in a VFS file system) should not
-                // have WEB-INF.classes in their package name.
-                classNames.add(StringUtils.removeStart(packageName, "WEB-INF.classes.") + name);
-            }
+        public String getName() {
+            return name;
         }
-    }
-
-    private List<String> jar(URL location) throws IOException {
-        URL url = fileManager.normalizeToFileProtocol(location);
-        if (url != null) {
-            InputStream in = url.openStream();
-            try {
-                JarInputStream jarStream = new JarInputStream(in);
-                return jar(jarStream);
-            } finally {
-                in.close();
-            }
-        } else if (LOG.isDebugEnabled())
-            LOG.debug("Unable to read [#0]", location.toExternalForm());
-        
-        return Collections.emptyList();
-    }
-
-    private List<String> jar(JarInputStream jarStream) throws IOException {
-        List<String> classNames = new ArrayList<String>();
-
-        JarEntry entry;
-        while ((entry = jarStream.getNextJarEntry()) != null) {
-            if (entry.isDirectory() || !entry.getName().endsWith(".class")) {
-                continue;
-            }
-            String className = entry.getName();
-            className = className.replaceFirst(".class$", "");
 
-            //war files are treated as .jar files, so takeout WEB-INF/classes
-            className = StringUtils.removeStart(className, "WEB-INF/classes/"); 
-
-            className = className.replace('/', '.');
-            classNames.add(className);
+        @Override
+        public String toString() {
+            return name;
         }
-
-        return classNames;
     }
 
     public class Annotatable {
@@ -467,12 +83,6 @@ public class ClassFinder {
 
     }
 
-    public static interface Info {
-        String getName();
-
-        List<AnnotationInfo> getAnnotations();
-    }
-
     public class PackageInfo extends Annotatable implements Info {
         private final String name;
         private final ClassInfo info;
@@ -485,8 +95,8 @@ public class ClassFinder {
             this.info = null;
         }
 
-        public PackageInfo(String name) {
-            info = new ClassInfo(name, null);
+        public PackageInfo(String name, ClassFinder classFinder) {
+            info = new ClassInfo(name, null, classFinder);
             this.name = name;
             this.pkg = null;
         }
@@ -509,19 +119,22 @@ public class ClassFinder {
         private final List<String> superInterfaces = new ArrayList<String>();
         private final List<FieldInfo> fields = new ArrayList<FieldInfo>();
         private Class<?> clazz;
+        private ClassFinder classFinder;
         private ClassNotFoundException notFound;
 
-        public ClassInfo(Class clazz) {
+        public ClassInfo(Class clazz, ClassFinder classFinder) {
             super(clazz);
             this.clazz = clazz;
+            this.classFinder = classFinder;
             this.name = clazz.getName();
             Class superclass = clazz.getSuperclass();
             this.superType = superclass != null ? superclass.getName(): null;
         }
 
-        public ClassInfo(String name, String superType) {
+        public ClassInfo(String name, String superType, ClassFinder classFinder) {
             this.name = name;
             this.superType = superType;
+            this.classFinder = classFinder;
         }
 
         public String getPackageName(){
@@ -560,10 +173,10 @@ public class ClassFinder {
             if (clazz != null) return clazz;
             if (notFound != null) throw notFound;
             try {
-                this.clazz = classLoaderInterface.loadClass(name);
+                this.clazz = classFinder.getClassLoaderInterface().loadClass(name);
                 return clazz;
             } catch (ClassNotFoundException notFound) {
-                classesNotLoaded.add(name);
+                classFinder.getClassesNotLoaded().add(name);
                 this.notFound = notFound;
                 throw notFound;
             }
@@ -669,179 +282,4 @@ public class ClassFinder {
         }
     }
 
-    public class AnnotationInfo extends Annotatable implements Info {
-        private final String name;
-
-        public AnnotationInfo(Annotation annotation){
-            this(annotation.getClass().getName());
-        }
-
-        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;
-        }
-
-        @Override
-        public String toString() {
-            return name;
-        }
-    }
-
-    private List<Info> getAnnotationInfos(String name) {
-        List<Info> infos = annotated.get(name);
-        if (infos == null) {
-            infos = new ArrayList<Info>();
-            annotated.put(name, infos);
-        }
-        return infos;
-    }
-
-    private void readClassDef(String className) {
-        if (!className.endsWith(".class")) {
-            className = className.replace('.', '/') + ".class";
-        }
-        try {
-            URL resource = classLoaderInterface.getResource(className);
-            if (resource != null) {
-                InputStream in = resource.openStream();
-                try {
-                    ClassReader classReader = new ClassReader(in);
-                    classReader.accept(new InfoBuildingClassVisitor(), ClassReader.SKIP_DEBUG);
-                } finally {
-                    in.close();
-                }
-            } else {
-                throw new XWorkException("Could not load " + className);
-            }
-        } catch (IOException e) {
-            throw new XWorkException("Could not load " + className, e);
-        }
-
-    }
-
-    public class InfoBuildingClassVisitor extends ClassVisitor {
-        private Info info;
-
-        public InfoBuildingClassVisitor() {
-            super(Opcodes.ASM5);
-        }
-
-        public InfoBuildingClassVisitor(Info info) {
-            this();
-            this.info = info;
-        }
-
-        @Override
-        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;
-                classInfos.put(classInfo.getName(), classInfo);
-
-                if (extractBaseInterfaces)
-                    extractSuperInterfaces(classInfo);
-            }
-        }
-
-        private void extractSuperInterfaces(ClassInfo classInfo) {
-            String superType = classInfo.getSuperType();
-
-            if (superType != null) {
-                ClassInfo base = classInfos.get(superType);
-
-                if (base == null) {
-                    //try to load base
-                    String resource = superType.replace('.', '/') + ".class";
-                    readClassDef(resource);
-                    base = classInfos.get(superType);
-                }
-
-                if (base != null) {
-                    List<String> interfaces = classInfo.getSuperInterfaces();
-                    interfaces.addAll(base.getSuperInterfaces());
-                    interfaces.addAll(base.getInterfaces());
-                }
-            }
-        }
-
-        private String javaName(String name) {
-            return (name == null)? null:name.replace('/', '.');
-        }
-
-        @Override
-        public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
-            AnnotationInfo annotationInfo = new AnnotationInfo(desc);
-            info.getAnnotations().add(annotationInfo);
-            getAnnotationInfos(annotationInfo.getName()).add(info);
-            return null;
-        }
-
-        @Override
-        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 null;
-        }
-
-        @Override
-        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 InfoBuildingMethodVisitor(methodInfo);
-        }
-    }
-
-    public class InfoBuildingMethodVisitor extends MethodVisitor {
-        private Info info;
-
-        public InfoBuildingMethodVisitor() {
-            super(Opcodes.ASM5);
-        }
-
-        public InfoBuildingMethodVisitor(Info info) {
-            this();
-            this.info = info;
-        }
-
-        @Override
-        public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
-            AnnotationInfo annotationInfo = new AnnotationInfo(desc);
-            info.getAnnotations().add(annotationInfo);
-            getAnnotationInfos(annotationInfo.getName()).add(info);
-            return null;
-        }
-
-        @Override
-        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 null;
-        }
-    }
-
-    private static final class DefaultClassnameFilterImpl implements Test<String> {
-        public boolean test(String className) {
-            return true;
-        }
-    }
 }
-

http://git-wip-us.apache.org/repos/asf/struts/blob/3ce21ac4/xwork-core/src/main/java/com/opensymphony/xwork2/util/finder/DefaultClassFinder.java
----------------------------------------------------------------------
diff --git a/xwork-core/src/main/java/com/opensymphony/xwork2/util/finder/DefaultClassFinder.java b/xwork-core/src/main/java/com/opensymphony/xwork2/util/finder/DefaultClassFinder.java
new file mode 100644
index 0000000..192196a
--- /dev/null
+++ b/xwork-core/src/main/java/com/opensymphony/xwork2/util/finder/DefaultClassFinder.java
@@ -0,0 +1,609 @@
+/*
+ * Copyright 2002-2003,2009 The Apache Software Foundation.
+ * 
+ * Licensed 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 com.opensymphony.xwork2.util.finder;
+
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.FileManager;
+import com.opensymphony.xwork2.FileManagerFactory;
+import com.opensymphony.xwork2.XWorkException;
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.xwork2.util.logging.LoggerFactory;
+import org.apache.commons.lang3.StringUtils;
+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.JarURLConnection;
+import java.net.URL;
+import java.net.URLDecoder;
+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.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+
+/**
+ * ClassFinder searches the classpath of the specified ClassLoaderInterface 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 DefaultClassFinder implements ClassFinder {
+    private static final Logger LOG = LoggerFactory.getLogger(DefaultClassFinder.class);
+
+    private final Map<String, List<Info>> annotated = new HashMap<String, List<Info>>();
+    private final Map<String, ClassInfo> classInfos = new LinkedHashMap<String, ClassInfo>();
+
+    private final List<String> classesNotLoaded = new ArrayList<String>();
+
+    private boolean extractBaseInterfaces;
+    private ClassLoaderInterface classLoaderInterface;
+    private FileManager fileManager;
+
+    public DefaultClassFinder(ClassLoaderInterface classLoaderInterface, Collection<URL> urls, boolean extractBaseInterfaces, Set<String> protocols, Test<String> classNameFilter) {
+        this.classLoaderInterface = classLoaderInterface;
+        this.extractBaseInterfaces = extractBaseInterfaces;
+        this.fileManager = ActionContext.getContext().getInstance(FileManagerFactory.class).getFileManager();
+
+        List<String> classNames = new ArrayList<String>();
+        for (URL location : urls) {
+            try {
+                if (protocols.contains(location.getProtocol())) {
+                    classNames.addAll(jar(location));
+                } else if ("file".equals(location.getProtocol())) {
+                    try {
+                        // See if it's actually a jar
+                        URL jarUrl = new URL("jar", "", location.toExternalForm() + "!/");
+                        JarURLConnection juc = (JarURLConnection) jarUrl.openConnection();
+                        juc.getJarFile();
+                        classNames.addAll(jar(jarUrl));
+                    } catch (IOException e) {
+                        classNames.addAll(file(location));
+                    }
+                }
+            } catch (Exception e) {
+                if (LOG.isErrorEnabled())
+                    LOG.error("Unable to read URL [#0]", e, location.toExternalForm());
+            }
+        }
+
+        for (String className : classNames) {
+            try {
+                if (classNameFilter.test(className))
+                    readClassDef(className);
+            } catch (Throwable e) {
+                if (LOG.isErrorEnabled())
+                    LOG.error("Unable to read class [#0]", e, className);
+            }
+        }
+    }
+
+    public DefaultClassFinder(Class... classes){
+        this(Arrays.asList(classes));
+    }
+
+    public DefaultClassFinder(List<Class> classes){
+        this.classLoaderInterface = null;
+        List<Info> infos = new ArrayList<Info>();
+        List<Package> packages = new ArrayList<Package>();
+        for (Class clazz : classes) {
+
+            Package aPackage = clazz.getPackage();
+            if (aPackage != null && !packages.contains(aPackage)){
+                infos.add(new PackageInfo(aPackage));
+                packages.add(aPackage);
+            }
+
+            ClassInfo classInfo = new ClassInfo(clazz, this);
+            infos.add(classInfo);
+            classInfos.put(classInfo.getName(), classInfo);
+            for (Method method : clazz.getDeclaredMethods()) {
+                infos.add(new MethodInfo(classInfo, method));
+            }
+
+            for (Constructor constructor : clazz.getConstructors()) {
+                infos.add(new MethodInfo(classInfo, constructor));
+            }
+
+            for (Field field : clazz.getDeclaredFields()) {
+                infos.add(new FieldInfo(classInfo, field));
+            }
+        }
+
+        for (Info info : infos) {
+            for (AnnotationInfo annotation : info.getAnnotations()) {
+                List<Info> annotationInfos = getAnnotationInfos(annotation.getName());
+                annotationInfos.add(info);
+            }
+        }
+    }
+
+    public ClassLoaderInterface getClassLoaderInterface() {
+        return classLoaderInterface;
+    }
+
+    public boolean isAnnotationPresent(Class<? extends Annotation> annotation) {
+        List<Info> infos = annotated.get(annotation.getName());
+        return infos != null && !infos.isEmpty();
+    }
+
+    /**
+     * 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.  Once obtained, the returned list will be a live view of the
+     * results from the last findAnnotated* method call.
+     * <p/>
+     * This method is not thread safe.
+     * @return an unmodifiable live view of classes that could not be loaded in previous findAnnotated* call.
+     */
+    public List<String> getClassesNotLoaded() {
+        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) {
+        classesNotLoaded.clear();
+        List<Class> classes = new ArrayList<Class>();
+        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 (Throwable e) {
+                    if (LOG.isErrorEnabled())
+                        LOG.error("Error loading class [#0]", e, classInfo.getName());
+                    classesNotLoaded.add(classInfo.getName());
+                }
+            }
+        }
+        return classes;
+    }
+
+    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 && !"<init>".equals(info.getName())) {
+                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 (Throwable e) {
+                    if (LOG.isErrorEnabled())
+                        LOG.error("Error loading class [#0]", e, classInfo.getName());
+                    classesNotLoaded.add(classInfo.getName());
+                }
+            }
+        }
+        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 && "<init>".equals(info.getName())) {
+                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 (Throwable e) {
+                    if (LOG.isErrorEnabled())
+                        LOG.error("Error loading class [#0]", e, classInfo.getName());
+                    classesNotLoaded.add(classInfo.getName());
+                }
+            }
+        }
+        return constructors;
+    }
+
+    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 (Throwable e) {
+                    if (LOG.isErrorEnabled())
+                        LOG.error("Error loading class [#0]", e, classInfo.getName());
+                    classesNotLoaded.add(classInfo.getName());
+                }
+            }
+        }
+        return fields;
+    }
+
+    public List<Class> findClassesInPackage(String packageName, boolean recursive) {
+        classesNotLoaded.clear();
+        List<Class> classes = new ArrayList<Class>();
+        for (ClassInfo classInfo : classInfos.values()) {
+            try {
+                if (recursive && classInfo.getPackageName().startsWith(packageName)){
+                    classes.add(classInfo.get());
+                } else if (classInfo.getPackageName().equals(packageName)){
+                    classes.add(classInfo.get());
+                }
+            } catch (Throwable e) {
+                if (LOG.isErrorEnabled())
+                    LOG.error("Error loading class [#0]", e, classInfo.getName());
+                classesNotLoaded.add(classInfo.getName());
+            }
+        }
+        return classes;
+    }
+
+    public List<Class> findClasses(Test<ClassInfo> test) {
+        classesNotLoaded.clear();
+        List<Class> classes = new ArrayList<Class>();
+        for (ClassInfo classInfo : classInfos.values()) {
+            try {
+                if (test.test(classInfo)) {
+                    classes.add(classInfo.get());
+                }
+            } catch (Throwable e) {
+                if (LOG.isErrorEnabled())
+                    LOG.error("Error loading class [#0]", e, classInfo.getName());
+                classesNotLoaded.add(classInfo.getName());
+            }
+        }
+        return classes;
+    }
+
+    public List<Class> findClasses() {
+        classesNotLoaded.clear();
+        List<Class> classes = new ArrayList<Class>();
+        for (ClassInfo classInfo : classInfos.values()) {
+            try {
+                classes.add(classInfo.get());
+            } catch (Throwable e) {
+                if (LOG.isErrorEnabled())
+                    LOG.error("Error loading class [#0]", e, classInfo.getName());
+                classesNotLoaded.add(classInfo.getName());
+            }
+        }
+        return classes;
+    }
+
+    private static List<URL> getURLs(ClassLoaderInterface classLoader, String[] dirNames) {
+        List<URL> urls = new ArrayList<URL>();
+        for (String dirName : dirNames) {
+            try {
+                Enumeration<URL> classLoaderURLs = classLoader.getResources(dirName);
+                while (classLoaderURLs.hasMoreElements()) {
+                    URL url = classLoaderURLs.nextElement();
+                    urls.add(url);
+                }
+            } catch (IOException ioe) {
+                if (LOG.isErrorEnabled())
+                    LOG.error("Could not read driectory [#0]", ioe, dirName);
+            }
+        }
+
+        return urls;
+    }
+
+    private List<String> file(URL location) {
+        List<String> classNames = new ArrayList<String>();
+        File dir = new File(URLDecoder.decode(location.getPath()));
+        if ("META-INF".equals(dir.getName())) {
+            dir = dir.getParentFile(); // Scrape "META-INF" off
+        }
+        if (dir.isDirectory()) {
+            scanDir(dir, classNames, "");
+        }
+        return classNames;
+    }
+
+    private void scanDir(File dir, List<String> classNames, String packageName) {
+        File[] files = dir.listFiles();
+        for (File file : files) {
+            if (file.isDirectory()) {
+                scanDir(file, classNames, packageName + file.getName() + ".");
+            } else if (file.getName().endsWith(".class")) {
+                String name = file.getName();
+                name = name.replaceFirst(".class$", "");
+                // Classes packaged in an exploded .war (e.g. in a VFS file system) should not
+                // have WEB-INF.classes in their package name.
+                classNames.add(StringUtils.removeStart(packageName, "WEB-INF.classes.") + name);
+            }
+        }
+    }
+
+    private List<String> jar(URL location) throws IOException {
+        URL url = fileManager.normalizeToFileProtocol(location);
+        if (url != null) {
+            InputStream in = url.openStream();
+            try {
+                JarInputStream jarStream = new JarInputStream(in);
+                return jar(jarStream);
+            } finally {
+                in.close();
+            }
+        } else if (LOG.isDebugEnabled())
+            LOG.debug("Unable to read [#0]", location.toExternalForm());
+        
+        return Collections.emptyList();
+    }
+
+    private List<String> jar(JarInputStream jarStream) throws IOException {
+        List<String> classNames = new ArrayList<String>();
+
+        JarEntry entry;
+        while ((entry = jarStream.getNextJarEntry()) != null) {
+            if (entry.isDirectory() || !entry.getName().endsWith(".class")) {
+                continue;
+            }
+            String className = entry.getName();
+            className = className.replaceFirst(".class$", "");
+
+            //war files are treated as .jar files, so takeout WEB-INF/classes
+            className = StringUtils.removeStart(className, "WEB-INF/classes/"); 
+
+            className = className.replace('/', '.');
+            classNames.add(className);
+        }
+
+        return classNames;
+    }
+
+    public class PackageInfo extends Annotatable implements Info {
+        private final String name;
+        private final ClassInfo info;
+        private final Package pkg;
+
+        public PackageInfo(Package pkg){
+            super(pkg);
+            this.pkg = pkg;
+            this.name = pkg.getName();
+            this.info = null;
+        }
+
+        public PackageInfo(String name, ClassFinder classFinder) {
+            info = new ClassInfo(name, null, classFinder);
+            this.name = name;
+            this.pkg = null;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public Package get() throws ClassNotFoundException {
+            return (pkg != null)?pkg:info.get().getPackage();
+        }
+    }
+
+    private List<Info> getAnnotationInfos(String name) {
+        List<Info> infos = annotated.get(name);
+        if (infos == null) {
+            infos = new ArrayList<Info>();
+            annotated.put(name, infos);
+        }
+        return infos;
+    }
+
+    private void readClassDef(String className) {
+        if (!className.endsWith(".class")) {
+            className = className.replace('.', '/') + ".class";
+        }
+        try {
+            URL resource = classLoaderInterface.getResource(className);
+            if (resource != null) {
+                InputStream in = resource.openStream();
+                try {
+                    ClassReader classReader = new ClassReader(in);
+                    classReader.accept(new InfoBuildingVisitor(this), ClassReader.SKIP_DEBUG);
+                } finally {
+                    in.close();
+                }
+            } else {
+                throw new XWorkException("Could not load " + className);
+            }
+        } catch (IOException e) {
+            throw new XWorkException("Could not load " + className, e);
+        }
+
+    }
+
+    public class InfoBuildingVisitor extends EmptyVisitor {
+        private Info info;
+        private ClassFinder classFinder;
+
+        public InfoBuildingVisitor(ClassFinder classFinder) {
+            this.classFinder = classFinder;
+        }
+
+        public InfoBuildingVisitor(Info info, ClassFinder classFinder) {
+            this.info = info;
+            this.classFinder = classFinder;
+        }
+
+        @Override
+        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), classFinder);
+            } else {
+                ClassInfo classInfo = new ClassInfo(javaName(name), javaName(superName), classFinder);
+
+                for (String interfce : interfaces) {
+                    classInfo.getInterfaces().add(javaName(interfce));
+                }
+                info = classInfo;
+                classInfos.put(classInfo.getName(), classInfo);
+
+                if (extractBaseInterfaces)
+                    extractSuperInterfaces(classInfo);
+            }
+        }
+
+        private void extractSuperInterfaces(ClassInfo classInfo) {
+            String superType = classInfo.getSuperType();
+
+            if (superType != null) {
+                ClassInfo base = classInfos.get(superType);
+
+                if (base == null) {
+                    //try to load base
+                    String resource = superType.replace('.', '/') + ".class";
+                    readClassDef(resource);
+                    base = classInfos.get(superType);
+                }
+
+                if (base != null) {
+                    List<String> interfaces = classInfo.getSuperInterfaces();
+                    interfaces.addAll(base.getSuperInterfaces());
+                    interfaces.addAll(base.getInterfaces());
+                }
+            }
+        }
+
+        private String javaName(String name) {
+            return (name == null)? null:name.replace('/', '.');
+        }
+
+        @Override
+        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, classFinder);
+        }
+
+        @Override
+        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, classFinder);
+        }
+
+        @Override
+        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, classFinder);
+        }
+
+        @Override
+        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, classFinder);
+        }
+    }
+
+    private static final class DefaultClassnameFilterImpl implements Test<String> {
+        public boolean test(String className) {
+            return true;
+        }
+    }
+}
+


Mime
View raw message