annotatedclassscanner.java

来自「resetful样式的ws样例,一种面向资源的webservices服务」· Java 代码 · 共 438 行

JAVA
438
字号
/* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. *  * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. *  * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development * and Distribution License("CDDL") (collectively, the "License").  You * may not use this file except in compliance with the License. You can obtain * a copy of the License at https://jersey.dev.java.net/CDDL+GPL.html * or jersey/legal/LICENSE.txt.  See the License for the specific * language governing permissions and limitations under the License. *  * When distributing the software, include this License Header Notice in each * file and include the License file at jersey/legal/LICENSE.txt. * Sun designates this particular file as subject to the "Classpath" exception * as provided by Sun in the GPL Version 2 section of the License file that * accompanied this code.  If applicable, add the following below the License * Header, with the fields enclosed by brackets [] replaced by your own * identifying information: "Portions Copyrighted [year] * [name of copyright owner]" *  * Contributor(s): *  * If you wish your version of this file to be governed by only the CDDL or * only the GPL Version 2, indicate your decision by adding "[Contributor] * elects to include this software in this distribution under the [CDDL or GPL * Version 2] license."  If you don't indicate a single choice of license, a * recipient has the option to distribute your version of this file under * either the CDDL, the GPL Version 2 or to extend the choice of license to * its licensees as provided above.  However, if you add GPL Version 2 code * and therefore, elected the GPL Version 2 license, then the option applies * only if the new code is made subject to such option by the copyright * holder. */package com.sun.jersey.impl.container.config;import java.io.File;import java.io.IOException;import java.io.InputStream;import java.lang.annotation.Annotation;import java.net.URI;import java.net.URISyntaxException;import java.net.URL;import java.util.Enumeration;import java.util.HashSet;import java.util.Set;import java.util.jar.JarEntry;import java.util.jar.JarFile;import java.util.logging.Level;import java.util.logging.Logger;import org.objectweb.asm.AnnotationVisitor;import org.objectweb.asm.Attribute;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;/** * Search for Java classes that are annotated with one or more of a set * of annotations. * <p> * The search is restricted to Java classes that are publically scoped. * Inner static public classes are also searched. *  * @author Frank D. Martinez. fmartinez@asimovt.com */public final class AnnotatedClassScanner {    private static final Logger LOGGER =             Logger.getLogger(AnnotatedClassScanner.class.getName());        /** Matching annotated classes. */    private Set<Class> classes;        /** Set of annotations to search for. */    private final Set<String> annotations;        /** The class loader to use to load matching Java class files */    private final ClassLoader classloader;        /**     *      * @param annotations the set of annotations to match     */    public AnnotatedClassScanner(Class... annotations) {        this.classloader = Thread.currentThread().getContextClassLoader();        this.annotations = getAnnotationSet(annotations);        this.classes = new HashSet<Class>();    }        /**     * Scans paths for matching Java classes     *      * @param paths An array of absolute paths to search.     * @return The set of matching classes that are annotated with one or more of     *         the specified annotations.     */    public Set<Class> scan(File[] paths) {        this.classes = new HashSet<Class>();                for (File file : paths) {            index(file);        }        return classes;    }    /**     * Scans packages for matching Java classes.     *      * @param packages An array of packages to search.     * @return The set of matching classes that are annotated with one or more of     *         the specified annotations.     */    public Set<Class> scan(String[] packages) {        this.classes = new HashSet<Class>();                for (String p : packages) {            try {                String fileP = p.replace('.', '/');                Enumeration<URL> urls = classloader.getResources(fileP);                while (urls.hasMoreElements()) {                    URL url = urls.nextElement();                    try {                        URI uri = url.toURI();                        index(uri, fileP);                    } catch (URISyntaxException e) {                        LOGGER.warning("URL, " +                                 url +                                 "cannot be converted to a URI");                                            }                }            } catch (IOException ex) {                String s = "The resources for the package" +                         p +                         ", could not be obtained";                LOGGER.severe(s);                throw new RuntimeException(s, ex);            }        }                return classes;    }        /**     * Get the current set of matching classes.     *      * @return The set of matching classes that are annotated with one or more of     *         the specified annotations.     */    public Set<Class> getMatchingClasses() {        return classes;    }        /**     * Get the current set of classes that match a set of annotations.     *      * @param annotations the set of matching annotations     * @return The set of matching classes that are annotated with one or more of     *         the specified annotations.     */    public Set<Class<?>> getMatchingClasses(Class... annotations) {        Set<Class<?>> s = new HashSet<Class<?>>();        for (Class<?> c : classes) {            if (hasAnnotations(c, annotations))                s.add(c);        }        return s;    }        @SuppressWarnings("unchecked")    private boolean hasAnnotations(Class c, Class... annotations) {        Annotation[] _as = c.getAnnotations();        for (Class a : annotations) {            if (c.getAnnotation(a) == null) return false;        }                return true;    }        private Set<String> getAnnotationSet(Class... annotations) {        Set<String> a = new HashSet<String>();        for (Class cls : annotations) {            a.add(                "L" + cls.getName().replaceAll("\\.", "/") + ";");        }        return a;    }        private void index(File file) {        if (file.isDirectory()) {            indexDir(file, true);        } else if (file.getName().endsWith(".jar") ||                 file.getName().endsWith(".zip")) {            indexJar(file);        } else {            LOGGER.warning("File, " +                     file.getAbsolutePath() +                     ", is ignored, it not a directory, a jar file or a zip file");        }    }        private void index(URI u, String filePackageName) {        String scheme = u.getScheme();        if (scheme.equals("file")) {            File f = new File(u.getPath());            if (f.isDirectory()) {                indexDir(f, false);            } else {                LOGGER.warning("URL, " +                         u +                         ", is ignored. The path, " +                         f.getPath() +                        ", is not a directory");                            }        } else if (scheme.equals("jar") || scheme.equals("zip")) {            URI jarUri = URI.create(u.getRawSchemeSpecificPart());            String jarFile = jarUri.getPath();            jarFile = jarFile.substring(0, jarFile.indexOf('!'));                        indexJar(new File(jarFile), filePackageName);        } else {            LOGGER.warning("URL, " +                     u +                     ", is ignored, it not a file or a jar file URL");                    }    }        private void indexDir(File root, boolean indexJars) {        for (File child : root.listFiles()) {            if (child.isDirectory()) {                indexDir(child, indexJars);            } else if (indexJars && child.getName().endsWith(".jar")) {                indexJar(child);            } else if (child.getName().endsWith(".class")) {                analyzeClassFile(child.toURI());            }        }            }        private void indexJar(File file) {        indexJar(file, "");    }    private void indexJar(File file, String parent) {        final JarFile jar = getJarFile(file);        try {            final Enumeration<JarEntry> entries = jar.entries();            while (entries.hasMoreElements()) {                JarEntry e = entries.nextElement();                if (!e.isDirectory() && e.getName().startsWith(parent) &&                        e.getName().endsWith(".class")) {                    analyzeClassFile(jar, e);                }            }        } catch (Exception e) {            LOGGER.log(Level.SEVERE, "Exception while processing file, " + file, e);        } finally {            try {                if (jar != null) {                    jar.close();                }            } catch (IOException ex) {                String s = "Error closing jar file, " +                        jar.getName();                LOGGER.severe(s);            }        }    }        private JarFile getJarFile(File file) {        if (file == null) {            return null;        }        try {            return new JarFile(file);        } catch (IOException ex) {            String s = "File, " +                     file.getAbsolutePath() +                    ", is not a jar file";            LOGGER.severe(s);            throw new RuntimeException(s, ex);        }    }        private void analyzeClassFile(URI classFileUri) {                getClassReader(classFileUri).accept(classVisitor, 0);    }        private void analyzeClassFile(JarFile jarFile, JarEntry entry) {                getClassReader(jarFile, entry).accept(classVisitor, 0);    }            private ClassReader getClassReader(JarFile jarFile, JarEntry entry) {        InputStream is = null;        try {            is = jarFile.getInputStream(entry);            ClassReader cr = new ClassReader(is);            return cr;        } catch (IOException ex) {            String s = "Error accessing input stream of the jar file, " +                     jarFile.getName() + ", entry, " + entry.getName();            LOGGER.severe(s);            throw new RuntimeException(s, ex);        } finally {            try {                if (is != null) {                   is.close();                }            } catch (IOException ex) {                String s = "Error closing input stream of the jar file, " +                     jarFile.getName() + ", entry, " + entry.getName() + ", closed.";                LOGGER.severe(s);            }        }    }        private ClassReader getClassReader(URI classFileUri) {        InputStream is = null;        try {            is = classFileUri.toURL().openStream();            ClassReader cr = new ClassReader(is);            return cr;        } catch (IOException ex) {            String s = "Error accessing input stream of the class file URI, " +                     classFileUri;            LOGGER.severe(s);            throw new RuntimeException(s, ex);        } finally {            try {                if (is != null) {                   is.close();                }            } catch (IOException ex) {            String s = "Error closing input stream of the class file URI, " +                     classFileUri;            LOGGER.severe(s);            }        }    }        private Class getClassForName(String className) {        try {            return classloader.loadClass(className);        } catch (ClassNotFoundException ex) {            String s = "A (root resource) class file of the class name, " +                     className +                     "is identified but the class could not be loaded";            LOGGER.severe(s);            throw new RuntimeException(s, ex);        }    }        private final AnnotatedClassVisitor classVisitor = new AnnotatedClassVisitor();        private final class AnnotatedClassVisitor implements ClassVisitor {        /**         * The name of the visited class.         */        private String className;                /**         * True if the class has the correct scope         */        private boolean isScoped;                        /**         * True if the class has the correct declared annotations         */        private boolean isAnnotated;                public void visit(int version, int access, String name,                 String signature, String superName, String[] interfaces) {            className = name;            isScoped = (access & Opcodes.ACC_PUBLIC) != 0;            isAnnotated = false;        }                public AnnotationVisitor visitAnnotation(String desc, boolean visible) {            isAnnotated |= annotations.contains(desc);            return null;        }                public void visitInnerClass(String name, String outerName,                 String innerName, int access) {            // If the name of the class that was visited is equal            // to the name of this visited inner class then            // this access field needs to be used for checking the scope            // of the inner class            if (className.equals(name)) {                isScoped = (access & Opcodes.ACC_PUBLIC) != 0;                                // Inner classes need to be statically scoped                isScoped &= (access & Opcodes.ACC_STATIC) == Opcodes.ACC_STATIC;            }        }                public void visitEnd() {            if (isScoped && isAnnotated) {                // Correctly scoped and annotated                // add to the set of matching classes.                classes.add(getClassForName(className.replaceAll("/", ".")));                }        }                        public void visitOuterClass(String string, String string0,                 String string1) {            // Do nothing        }                public FieldVisitor visitField(int i, String string,                 String string0, String string1, Object object) {            // Do nothing            return null;        }                public void visitSource(String string, String string0) {            // Do nothing        }                public void visitAttribute(Attribute attribute) {            // Do nothing        }                public MethodVisitor visitMethod(int i, String string,                 String string0, String string1, String[] string2) {            // Do nothing            return null;        }            };}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?