📄 classfinder.java
字号:
/*
* 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 + -