⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 classfinder.java

📁 测试工具
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */

package org.apache.jorphan.reflect;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeSet;
import java.util.zip.ZipFile;

import org.apache.jorphan.logging.LoggingManager;
import org.apache.jorphan.util.JOrphanUtils;
import org.apache.log.Logger;

/**
 * This class finds classes that extend one of a set of parent classes
 * 
 * @author Burt Beckwith
 * @author Michael Stover (mstover1 at apache.org)
 */
public final class ClassFinder {
    private static final Logger log = LoggingManager.getLoggerForClass();

    private static final String DOT_JAR = ".jar"; // $NON-NLS-1$
    private static final String DOT_CLASS = ".class"; // $NON-NLS-1$
    private static final int DOT_CLASS_LEN = DOT_CLASS.length();

    // static only
	private ClassFinder() {
	}
    
    /**
     * Filter updates to TreeSet by only storing classes
     * that extend one of the parent classes
     * 
     *
     */
    private static class FilterTreeSet extends TreeSet{
        private final Class[] parents; // parent classes to check
        private final boolean inner; // are inner classes OK?

        private final transient ClassLoader contextClassLoader 
            = Thread.currentThread().getContextClassLoader(); // Potentially expensive; do it once
        
        FilterTreeSet(Class []parents, boolean inner){
            super();
            this.parents=parents;
            this.inner=inner;
        }
        
        /**
         * Override the superclass so we only add classnames that
         * meet the criteria.
         * 
         * @param o - classname (must be a String)
         * @return true if it is a new entry
         * 
         * @see java.util.TreeSet#add(java.lang.Object)
         */
        public boolean add(Object o){
            if (contains(o)) return false;// No need to check it again
            String s = (String) o;// we only expect Strings
            if ((s.indexOf("$") == -1) || inner) { // $NON-NLS-1$
                if (isChildOf(parents,s, contextClassLoader)) {
                    return super.add(s);
                }
            }
            return false;
        }
    }

	/**
	 * Convenience method for 
     * <code>findClassesThatExtend(Class[], boolean)</code>
	 * with the option to include inner classes in the search set to false.
	 * 
	 * @return List containing discovered classes.
	 */
	public static List findClassesThatExtend(String[] paths, Class[] superClasses) 
        throws IOException {
		return findClassesThatExtend(paths, superClasses, false);
	}

    // For each directory in the search path, add all the jars found there
    private static String[] addJarsInPath(String[] paths) {
        Set fullList = new HashSet();
        for (int i = 0; i < paths.length; i++) {
            final String path = paths[i];
            fullList.add(path); // Keep the unexpanded path
            // TODO - allow directories to end with .jar by removing this check?
            if (!path.endsWith(DOT_JAR)) {
                File dir = new File(path);
                if (dir.exists() && dir.isDirectory()) {
                    String[] jars = dir.list(new FilenameFilter() {
                        public boolean accept(File f, String name) {
                            return name.endsWith(DOT_JAR);
                        }
                    });
                    for (int x = 0; x < jars.length; x++) {
                        fullList.add(jars[x]);
                    }
                }
            }
        }
        return (String[]) fullList.toArray(new String[0]);
    }

    /**
     * Find classes in the provided path(s)/jar(s) that extend the class(es).
     * @param strPathsOrJars - pathnames or jarfiles to search for classes
     * @param superClasses - required parent class(es)
     * @param innerClasses - should we include inner classes?
     * 
     * @return List containing discovered classes
     */
	public static List findClassesThatExtend(String[] strPathsOrJars, 
            final Class[] superClasses, final boolean innerClasses)
			throws IOException  {
        
		if (log.isDebugEnabled()) {
			for (int i = 0; i < superClasses.length ; i++){
				log.debug("superclass: "+superClasses[i].getName());  
			}
		}

        // Find all jars in the search path
		strPathsOrJars = addJarsInPath(strPathsOrJars);
        for (int k = 0; k < strPathsOrJars.length; k++) {
            strPathsOrJars[k] = fixPathEntry(strPathsOrJars[k]);
    		if (log.isDebugEnabled()) {
				log.debug("strPathsOrJars : " + strPathsOrJars[k]);
			}
		}
        
        // Now eliminate any classpath entries that do not "match" the search
		List listPaths = getClasspathMatches(strPathsOrJars);
		if (log.isDebugEnabled()) {
			Iterator tIter = listPaths.iterator();
			while (tIter.hasNext()) {
				log.debug("listPaths : " + tIter.next());
			}
		}
        
		Set listClasses = new FilterTreeSet(superClasses, innerClasses);
		// first get all the classes
		findClassesInPaths(listPaths, listClasses);
		if (log.isDebugEnabled()) {
            log.debug("listClasses.size()="+listClasses.size());
			Iterator tIter = listClasses.iterator();
			while (tIter.hasNext()) {
				log.debug("listClasses : " + tIter.next());
			}
		}
        
//        // Now keep only the required classes
//		Set subClassList = findAllSubclasses(superClasses, listClasses, innerClasses);
//        if (log.isDebugEnabled()) {
//            log.debug("subClassList.size()="+subClassList.size());
//            Iterator tIter = subClassList.iterator();
//            while (tIter.hasNext()) {
//                log.debug("subClassList : " + tIter.next());
//            }
//        }
        
		return new ArrayList(listClasses);//subClassList);
	}

    /*
     * Returns the classpath entries that match the search list of jars and paths
     */
	private static List getClasspathMatches(String[] strPathsOrJars) {
		log.debug("Classpath = " + System.getProperty("java.class.path")); // $NON-NLS-1$
        StringTokenizer stPaths = 
            new StringTokenizer(System.getProperty("java.class.path"), // $NON-NLS-1$ 
                System.getProperty("path.separator")); // $NON-NLS-1$
		if (log.isDebugEnabled()) {
			for (int i = 0; i < strPathsOrJars.length; i++) {
				log.debug("strPathsOrJars[" + i + "] : " + strPathsOrJars[i]);
			}
		}

		// find all jar files or paths that end with strPathOrJar

⌨️ 快捷键说明

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