You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by lu...@apache.org on 2016/11/23 10:59:47 UTC

[1/2] struts git commit: WW-4570 Cleans up ASM and assemblies

Repository: struts
Updated Branches:
  refs/heads/master 6f7fcaa33 -> 7872fa80f


WW-4570 Cleans up ASM and assemblies


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

Branch: refs/heads/master
Commit: f03279fc1ae1524272b08a4d5e031f7304ea05c5
Parents: 6f7fcaa
Author: Lukasz Lenart <lu...@apache.org>
Authored: Wed Nov 23 11:43:05 2016 +0100
Committer: Lukasz Lenart <lu...@apache.org>
Committed: Wed Nov 23 11:43:05 2016 +0100

----------------------------------------------------------------------
 assembly/src/main/assembly/all.xml     | 1 +
 assembly/src/main/assembly/lib.xml     | 1 +
 assembly/src/main/assembly/min-lib.xml | 5 +----
 pom.xml                                | 7 +++----
 4 files changed, 6 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/struts/blob/f03279fc/assembly/src/main/assembly/all.xml
----------------------------------------------------------------------
diff --git a/assembly/src/main/assembly/all.xml b/assembly/src/main/assembly/all.xml
index 8a05030..6d8fefb 100644
--- a/assembly/src/main/assembly/all.xml
+++ b/assembly/src/main/assembly/all.xml
@@ -31,6 +31,7 @@
   </formats>
   <dependencySets>
     <dependencySet>
+      <useProjectArtifact>false</useProjectArtifact>
       <outputDirectory>lib</outputDirectory>
       <scope>runtime</scope>
       <excludes>

http://git-wip-us.apache.org/repos/asf/struts/blob/f03279fc/assembly/src/main/assembly/lib.xml
----------------------------------------------------------------------
diff --git a/assembly/src/main/assembly/lib.xml b/assembly/src/main/assembly/lib.xml
index 7aa42dd..e25418d 100644
--- a/assembly/src/main/assembly/lib.xml
+++ b/assembly/src/main/assembly/lib.xml
@@ -31,6 +31,7 @@
   </formats>
   <dependencySets>
     <dependencySet>
+      <useProjectArtifact>false</useProjectArtifact>
       <outputDirectory>lib</outputDirectory>
       <scope>runtime</scope>
       <excludes>

http://git-wip-us.apache.org/repos/asf/struts/blob/f03279fc/assembly/src/main/assembly/min-lib.xml
----------------------------------------------------------------------
diff --git a/assembly/src/main/assembly/min-lib.xml b/assembly/src/main/assembly/min-lib.xml
index 10a18ff..f139dd0 100644
--- a/assembly/src/main/assembly/min-lib.xml
+++ b/assembly/src/main/assembly/min-lib.xml
@@ -31,7 +31,7 @@
   </formats>
   <dependencySets>
     <dependencySet>
-      <useProjectArtifact>true</useProjectArtifact>
+      <useProjectArtifact>false</useProjectArtifact>
       <useTransitiveDependencies>true</useTransitiveDependencies>
       <outputDirectory>lib</outputDirectory>
       <includes>
@@ -40,9 +40,6 @@
         <include>org.apache.commons:commons-lang3</include>
         <include>org.apache.logging.log4j:log4j-api</include>
         <include>ognl:ognl</include>
-        <include>org.ow2.asm:asm</include>
-        <include>org.ow2.asm:asm-tree</include>
-        <include>org.ow2.asm:asm-commons</include>
         <include>org.javassist:javassist</include>
         <include>commons-fileupload:commons-fileupload</include>
         <include>commons-io:commons-io</include>

http://git-wip-us.apache.org/repos/asf/struts/blob/f03279fc/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 62f8db9..7e3ed60 100644
--- a/pom.xml
+++ b/pom.xml
@@ -85,8 +85,7 @@
         <currentVersion>${project.version}</currentVersion>
         <struts2.springPlatformVersion>4.1.6.RELEASE</struts2.springPlatformVersion>
         <ognl.version>3.1.12</ognl.version>
-        <asm.version>3.3</asm.version>
-        <asm5.version>5.1</asm5.version>
+        <asm.version>5.1</asm.version>
         <tiles.version>3.0.7</tiles.version>
         <tiles-request.version>1.0.6</tiles-request.version>
         <log4j2.version>2.7</log4j2.version>
@@ -547,12 +546,12 @@
             <dependency>
                 <groupId>org.ow2.asm</groupId>
                 <artifactId>asm</artifactId>
-                <version>${asm5.version}</version>
+                <version>${asm.version}</version>
             </dependency>
             <dependency>
                 <groupId>org.ow2.asm</groupId>
                 <artifactId>asm-commons</artifactId>
-                <version>${asm5.version}</version>
+                <version>${asm.version}</version>
             </dependency>
             <dependency>
                 <groupId>junit</groupId>


[2/2] struts git commit: WW-4719 Moves DefaultClassFinder implementation into Convention and ASM dependencies

Posted by lu...@apache.org.
WW-4719 Moves DefaultClassFinder implementation into Convention and ASM dependencies


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

Branch: refs/heads/master
Commit: 7872fa80f957a3af72e760682c88a7283305f531
Parents: f03279f
Author: Lukasz Lenart <lu...@apache.org>
Authored: Wed Nov 23 11:59:32 2016 +0100
Committer: Lukasz Lenart <lu...@apache.org>
Committed: Wed Nov 23 11:59:32 2016 +0100

----------------------------------------------------------------------
 core/pom.xml                                    |   8 -
 .../xwork2/util/finder/DefaultClassFinder.java  | 580 ------------------
 plugins/convention/pom.xml                      |  10 +
 .../struts2/convention/DefaultClassFinder.java  | 583 +++++++++++++++++++
 4 files changed, 593 insertions(+), 588 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/struts/blob/7872fa80/core/pom.xml
----------------------------------------------------------------------
diff --git a/core/pom.xml b/core/pom.xml
index 9c59d91..cc2065b 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -267,14 +267,6 @@
             <artifactId>commons-lang3</artifactId>
         </dependency>
         <dependency>
-            <groupId>org.ow2.asm</groupId>
-            <artifactId>asm</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>org.ow2.asm</groupId>
-            <artifactId>asm-commons</artifactId>
-        </dependency>
-        <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-core</artifactId>
             <optional>true</optional>

http://git-wip-us.apache.org/repos/asf/struts/blob/7872fa80/core/src/main/java/com/opensymphony/xwork2/util/finder/DefaultClassFinder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/finder/DefaultClassFinder.java b/core/src/main/java/com/opensymphony/xwork2/util/finder/DefaultClassFinder.java
deleted file mode 100644
index aed42a8..0000000
--- a/core/src/main/java/com/opensymphony/xwork2/util/finder/DefaultClassFinder.java
+++ /dev/null
@@ -1,580 +0,0 @@
-/*
- * 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 org.apache.commons.lang3.StringUtils;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.objectweb.asm.AnnotationVisitor;
-import org.objectweb.asm.ClassReader;
-import org.objectweb.asm.ClassVisitor;
-import org.objectweb.asm.FieldVisitor;
-import org.objectweb.asm.MethodVisitor;
-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.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.*;
-import java.util.jar.JarEntry;
-import java.util.jar.JarInputStream;
-
-public class DefaultClassFinder implements ClassFinder {
-    private static final Logger LOG = LogManager.getLogger(DefaultClassFinder.class);
-
-    private final Map<String, List<Info>> annotated = new HashMap<>();
-    private final Map<String, ClassInfo> classInfos = new LinkedHashMap<>();
-
-    private final List<String> classesNotLoaded = new ArrayList<>();
-
-    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<>();
-        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) {
-                LOG.error("Unable to read URL [{}]", location.toExternalForm(), e);
-            }
-        }
-
-        for (String className : classNames) {
-            try {
-                if (classNameFilter.test(className))
-                    readClassDef(className);
-            } catch (Throwable e) {
-                LOG.error("Unable to read class [{}]", className, e);
-            }
-        }
-    }
-
-    public DefaultClassFinder(Class... classes){
-        this(Arrays.asList(classes));
-    }
-
-    public DefaultClassFinder(List<Class> classes){
-        this.classLoaderInterface = null;
-        List<Info> infos = new ArrayList<>();
-        List<Package> packages = new ArrayList<>();
-        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();
-    }
-
-    public List<String> getClassesNotLoaded() {
-        return Collections.unmodifiableList(classesNotLoaded);
-    }
-
-    public List<Package> findAnnotatedPackages(Class<? extends Annotation> annotation) {
-        classesNotLoaded.clear();
-        List<Package> packages = new ArrayList<>();
-        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<>();
-        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) {
-                    LOG.error("Error loading class [{}]", classInfo.getName(), e);
-                    classesNotLoaded.add(classInfo.getName());
-                }
-            }
-        }
-        return classes;
-    }
-
-    public List<Method> findAnnotatedMethods(Class<? extends Annotation> annotation) {
-        classesNotLoaded.clear();
-        List<ClassInfo> seen = new ArrayList<>();
-        List<Method> methods = new ArrayList<>();
-        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) {
-                    LOG.error("Error loading class [{}]", classInfo.getName(), e);
-                    classesNotLoaded.add(classInfo.getName());
-                }
-            }
-        }
-        return methods;
-    }
-
-    public List<Constructor> findAnnotatedConstructors(Class<? extends Annotation> annotation) {
-        classesNotLoaded.clear();
-        List<ClassInfo> seen = new ArrayList<>();
-        List<Constructor> constructors = new ArrayList<>();
-        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) {
-                    LOG.error("Error loading class [{}]", classInfo.getName(), e);
-                    classesNotLoaded.add(classInfo.getName());
-                }
-            }
-        }
-        return constructors;
-    }
-
-    public List<Field> findAnnotatedFields(Class<? extends Annotation> annotation) {
-        classesNotLoaded.clear();
-        List<ClassInfo> seen = new ArrayList<>();
-        List<Field> fields = new ArrayList<>();
-        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) {
-                    LOG.error("Error loading class [{}]", classInfo.getName(), e);
-                    classesNotLoaded.add(classInfo.getName());
-                }
-            }
-        }
-        return fields;
-    }
-
-    public List<Class> findClassesInPackage(String packageName, boolean recursive) {
-        classesNotLoaded.clear();
-        List<Class> classes = new ArrayList<>();
-        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) {
-                LOG.error("Error loading class [{}]", classInfo.getName(), e);
-                classesNotLoaded.add(classInfo.getName());
-            }
-        }
-        return classes;
-    }
-
-    public List<Class> findClasses(Test<ClassInfo> test) {
-        classesNotLoaded.clear();
-        List<Class> classes = new ArrayList<>();
-        for (ClassInfo classInfo : classInfos.values()) {
-            try {
-                if (test.test(classInfo)) {
-                    classes.add(classInfo.get());
-                }
-            } catch (Throwable e) {
-                LOG.error("Error loading class [{}]", classInfo.getName(), e);
-                classesNotLoaded.add(classInfo.getName());
-            }
-        }
-        return classes;
-    }
-
-    public List<Class> findClasses() {
-        classesNotLoaded.clear();
-        List<Class> classes = new ArrayList<>();
-        for (ClassInfo classInfo : classInfos.values()) {
-            try {
-                classes.add(classInfo.get());
-            } catch (Throwable e) {
-                LOG.error("Error loading class [{}]", classInfo.getName(), e);
-                classesNotLoaded.add(classInfo.getName());
-            }
-        }
-        return classes;
-    }
-
-    private static List<URL> getURLs(ClassLoaderInterface classLoader, String[] dirNames) {
-        List<URL> urls = new ArrayList<>();
-        for (String dirName : dirNames) {
-            try {
-                Enumeration<URL> classLoaderURLs = classLoader.getResources(dirName);
-                while (classLoaderURLs.hasMoreElements()) {
-                    URL url = classLoaderURLs.nextElement();
-                    urls.add(url);
-                }
-            } catch (IOException ioe) {
-                LOG.error("Could not read directory [{}]", dirName, ioe);
-            }
-        }
-
-        return urls;
-    }
-
-    private List<String> file(URL location) {
-        List<String> classNames = new ArrayList<>();
-        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 {
-            LOG.debug("Unable to read [{}]", location.toExternalForm());
-        }
-        return Collections.emptyList();
-    }
-
-    private List<String> jar(JarInputStream jarStream) throws IOException {
-        List<String> classNames = new ArrayList<>();
-
-        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<>();
-            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) {
-                try (InputStream in = resource.openStream()) {
-                    ClassReader classReader = new ClassReader(in);
-                    classReader.accept(new InfoBuildingVisitor(this), ClassReader.SKIP_DEBUG);
-                }
-            } else {
-                throw new XWorkException("Could not load " + className);
-            }
-        } catch (IOException e) {
-            throw new XWorkException("Could not load " + className, e);
-        }
-
-    }
-
-    public class InfoBuildingVisitor extends ClassVisitor {
-        private Info info;
-        private ClassFinder classFinder;
-
-        public InfoBuildingVisitor(ClassFinder classFinder) {
-            super(Opcodes.ASM5);
-            this.classFinder = classFinder;
-        }
-
-        public InfoBuildingVisitor(Info info, ClassFinder classFinder) {
-            this(classFinder);
-            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), 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 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;
-        }
-    }
-
-}
-

http://git-wip-us.apache.org/repos/asf/struts/blob/7872fa80/plugins/convention/pom.xml
----------------------------------------------------------------------
diff --git a/plugins/convention/pom.xml b/plugins/convention/pom.xml
index 740934b..1995924 100644
--- a/plugins/convention/pom.xml
+++ b/plugins/convention/pom.xml
@@ -33,6 +33,16 @@
             <artifactId>commons-lang3</artifactId>
         </dependency>
         <dependency>
+            <groupId>org.ow2.asm</groupId>
+            <artifactId>asm</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.ow2.asm</groupId>
+            <artifactId>asm-commons</artifactId>
+        </dependency>
+
+        <!-- testing -->
+        <dependency>
             <groupId>org.easymock</groupId>
             <artifactId>easymock</artifactId>
             <scope>test</scope>

http://git-wip-us.apache.org/repos/asf/struts/blob/7872fa80/plugins/convention/src/main/java/org/apache/struts2/convention/DefaultClassFinder.java
----------------------------------------------------------------------
diff --git a/plugins/convention/src/main/java/org/apache/struts2/convention/DefaultClassFinder.java b/plugins/convention/src/main/java/org/apache/struts2/convention/DefaultClassFinder.java
new file mode 100644
index 0000000..9412f7e
--- /dev/null
+++ b/plugins/convention/src/main/java/org/apache/struts2/convention/DefaultClassFinder.java
@@ -0,0 +1,583 @@
+/*
+ * 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 org.apache.struts2.convention;
+
+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.finder.ClassFinder;
+import com.opensymphony.xwork2.util.finder.ClassLoaderInterface;
+import com.opensymphony.xwork2.util.finder.Test;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+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.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.*;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+
+public class DefaultClassFinder implements ClassFinder {
+    private static final Logger LOG = LogManager.getLogger(DefaultClassFinder.class);
+
+    private final Map<String, List<Info>> annotated = new HashMap<>();
+    private final Map<String, ClassInfo> classInfos = new LinkedHashMap<>();
+
+    private final List<String> classesNotLoaded = new ArrayList<>();
+
+    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<>();
+        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) {
+                LOG.error("Unable to read URL [{}]", location.toExternalForm(), e);
+            }
+        }
+
+        for (String className : classNames) {
+            try {
+                if (classNameFilter.test(className))
+                    readClassDef(className);
+            } catch (Throwable e) {
+                LOG.error("Unable to read class [{}]", className, e);
+            }
+        }
+    }
+
+    public DefaultClassFinder(Class... classes){
+        this(Arrays.asList(classes));
+    }
+
+    public DefaultClassFinder(List<Class> classes){
+        this.classLoaderInterface = null;
+        List<Info> infos = new ArrayList<>();
+        List<Package> packages = new ArrayList<>();
+        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();
+    }
+
+    public List<String> getClassesNotLoaded() {
+        return Collections.unmodifiableList(classesNotLoaded);
+    }
+
+    public List<Package> findAnnotatedPackages(Class<? extends Annotation> annotation) {
+        classesNotLoaded.clear();
+        List<Package> packages = new ArrayList<>();
+        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<>();
+        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) {
+                    LOG.error("Error loading class [{}]", classInfo.getName(), e);
+                    classesNotLoaded.add(classInfo.getName());
+                }
+            }
+        }
+        return classes;
+    }
+
+    public List<Method> findAnnotatedMethods(Class<? extends Annotation> annotation) {
+        classesNotLoaded.clear();
+        List<ClassInfo> seen = new ArrayList<>();
+        List<Method> methods = new ArrayList<>();
+        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) {
+                    LOG.error("Error loading class [{}]", classInfo.getName(), e);
+                    classesNotLoaded.add(classInfo.getName());
+                }
+            }
+        }
+        return methods;
+    }
+
+    public List<Constructor> findAnnotatedConstructors(Class<? extends Annotation> annotation) {
+        classesNotLoaded.clear();
+        List<ClassInfo> seen = new ArrayList<>();
+        List<Constructor> constructors = new ArrayList<>();
+        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) {
+                    LOG.error("Error loading class [{}]", classInfo.getName(), e);
+                    classesNotLoaded.add(classInfo.getName());
+                }
+            }
+        }
+        return constructors;
+    }
+
+    public List<Field> findAnnotatedFields(Class<? extends Annotation> annotation) {
+        classesNotLoaded.clear();
+        List<ClassInfo> seen = new ArrayList<>();
+        List<Field> fields = new ArrayList<>();
+        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) {
+                    LOG.error("Error loading class [{}]", classInfo.getName(), e);
+                    classesNotLoaded.add(classInfo.getName());
+                }
+            }
+        }
+        return fields;
+    }
+
+    public List<Class> findClassesInPackage(String packageName, boolean recursive) {
+        classesNotLoaded.clear();
+        List<Class> classes = new ArrayList<>();
+        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) {
+                LOG.error("Error loading class [{}]", classInfo.getName(), e);
+                classesNotLoaded.add(classInfo.getName());
+            }
+        }
+        return classes;
+    }
+
+    public List<Class> findClasses(Test<ClassInfo> test) {
+        classesNotLoaded.clear();
+        List<Class> classes = new ArrayList<>();
+        for (ClassInfo classInfo : classInfos.values()) {
+            try {
+                if (test.test(classInfo)) {
+                    classes.add(classInfo.get());
+                }
+            } catch (Throwable e) {
+                LOG.error("Error loading class [{}]", classInfo.getName(), e);
+                classesNotLoaded.add(classInfo.getName());
+            }
+        }
+        return classes;
+    }
+
+    public List<Class> findClasses() {
+        classesNotLoaded.clear();
+        List<Class> classes = new ArrayList<>();
+        for (ClassInfo classInfo : classInfos.values()) {
+            try {
+                classes.add(classInfo.get());
+            } catch (Throwable e) {
+                LOG.error("Error loading class [{}]", classInfo.getName(), e);
+                classesNotLoaded.add(classInfo.getName());
+            }
+        }
+        return classes;
+    }
+
+    private static List<URL> getURLs(ClassLoaderInterface classLoader, String[] dirNames) {
+        List<URL> urls = new ArrayList<>();
+        for (String dirName : dirNames) {
+            try {
+                Enumeration<URL> classLoaderURLs = classLoader.getResources(dirName);
+                while (classLoaderURLs.hasMoreElements()) {
+                    URL url = classLoaderURLs.nextElement();
+                    urls.add(url);
+                }
+            } catch (IOException ioe) {
+                LOG.error("Could not read directory [{}]", dirName, ioe);
+            }
+        }
+
+        return urls;
+    }
+
+    private List<String> file(URL location) {
+        List<String> classNames = new ArrayList<>();
+        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 {
+            LOG.debug("Unable to read [{}]", location.toExternalForm());
+        }
+        return Collections.emptyList();
+    }
+
+    private List<String> jar(JarInputStream jarStream) throws IOException {
+        List<String> classNames = new ArrayList<>();
+
+        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<>();
+            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) {
+                try (InputStream in = resource.openStream()) {
+                    ClassReader classReader = new ClassReader(in);
+                    classReader.accept(new InfoBuildingVisitor(this), ClassReader.SKIP_DEBUG);
+                }
+            } else {
+                throw new XWorkException("Could not load " + className);
+            }
+        } catch (IOException e) {
+            throw new XWorkException("Could not load " + className, e);
+        }
+
+    }
+
+    public class InfoBuildingVisitor extends ClassVisitor {
+        private Info info;
+        private ClassFinder classFinder;
+
+        public InfoBuildingVisitor(ClassFinder classFinder) {
+            super(Opcodes.ASM5);
+            this.classFinder = classFinder;
+        }
+
+        public InfoBuildingVisitor(Info info, ClassFinder classFinder) {
+            this(classFinder);
+            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), 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 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;
+        }
+    }
+
+}
+