Java 如何在运行时从文件夹或JAR加载类?
我正在尝试制作一个Java工具,它将扫描Java应用程序的结构,并提供一些有意义的信息。为此,我需要能够扫描项目位置(JAR/WAR或一个文件夹)中的所有.class文件,并使用反射来阅读它们的方法。事实证明,这几乎是不可能的 我可以找到许多基于URLClassloader的解决方案,这些解决方案允许我从目录/归档中加载特定的类,但没有一个解决方案允许我在没有任何类名或包结构信息的情况下加载类 编辑:Java 如何在运行时从文件夹或JAR加载类?,java,class,reflection,jar,load,Java,Class,Reflection,Jar,Load,我正在尝试制作一个Java工具,它将扫描Java应用程序的结构,并提供一些有意义的信息。为此,我需要能够扫描项目位置(JAR/WAR或一个文件夹)中的所有.class文件,并使用反射来阅读它们的方法。事实证明,这几乎是不可能的 我可以找到许多基于URLClassloader的解决方案,这些解决方案允许我从目录/归档中加载特定的类,但没有一个解决方案允许我在没有任何类名或包结构信息的情况下加载类 编辑: 我想我的措辞很糟糕。我的问题不是我不能得到所有的类文件,我可以用递归等方法来实现,并正确地定位
我想我的措辞很糟糕。我的问题不是我不能得到所有的类文件,我可以用递归等方法来实现,并正确地定位它们。我的问题是为每个类文件获取一个类对象 以下代码从JAR文件加载所有类。它不需要知道任何关于类的信息。类的名称是从JarEntry中提取的
JarFile jarFile = new JarFile(pathToJar);
Enumeration<JarEntry> e = jarFile.entries();
URL[] urls = { new URL("jar:file:" + pathToJar+"!/") };
URLClassLoader cl = URLClassLoader.newInstance(urls);
while (e.hasMoreElements()) {
JarEntry je = e.nextElement();
if(je.isDirectory() || !je.getName().endsWith(".class")){
continue;
}
// -6 because of .class
String className = je.getName().substring(0,je.getName().length()-6);
className = className.replace('/', '.');
Class c = cl.loadClass(className);
}
从ctClass中,您可以获得所有方法、字段、嵌套类等。。。。
请看一下javassist api:
为此,我需要能够扫描项目位置(JAR/WAR或一个文件夹)中的所有.class文件
扫描文件夹中的所有文件很简单。一个选项是在表示文件夹的文件上调用File.listFiles()
,然后迭代生成的数组。要遍历嵌套文件夹的树,请使用递归
可以使用JarFile
API来扫描JAR文件的文件。。。您不需要递归来遍历嵌套的“文件夹”
这两个问题都不是特别复杂。只需阅读javadoc并开始编码。列出jar文件中的所有类
public static List getClasseNames(String jarName) {
ArrayList classes = new ArrayList();
if (debug)
System.out.println("Jar " + jarName );
try {
JarInputStream jarFile = new JarInputStream(new FileInputStream(
jarName));
JarEntry jarEntry;
while (true) {
jarEntry = jarFile.getNextJarEntry();
if (jarEntry == null) {
break;
}
if (jarEntry.getName().endsWith(".class")) {
if (debug)
System.out.println("Found "
+ jarEntry.getName().replaceAll("/", "\\."));
classes.add(jarEntry.getName().replaceAll("/", "\\."));
}
}
} catch (Exception e) {
e.printStackTrace();
}
return classes;
}
来到这里有类似的要求:
在某个包中有许多正在开发的服务类,这些类实现了一个通用的
接口,并希望在运行时检测它们
部分问题是在特定包中查找类,其中应用程序可以从jar文件或包/文件夹结构中的未打包类加载
所以我把Amingh和an的解决方案放在一起
// Retrieve classes of a package and it's nested package from file based class repository
package esc;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
public class GetClasses
{
private static boolean debug = false;
/**
* test function with assumed package esc.util
*/
public static void main(String... args)
{
try
{
final Class<?>[] list = getClasses("esc.util");
for (final Class<?> c : list)
{
System.out.println(c.getName());
}
}
catch (final IOException e)
{
e.printStackTrace();
}
}
/**
* Scans all classes accessible from the context class loader which belong to the given package and subpackages.
*
* @precondition Thread Class loader attracts class and jar files, exclusively
* @precondition Classes with static code sections are executed, when loaded and thus must not throw exceptions
*
* @param packageName
* [in] The base package path, dot-separated
*
* @return The classes of package /packageName/ and nested packages
*
* @throws IOException,
* ClassNotFoundException not applicable
*
* @author Sam Ginrich, http://www.java2s.com/example/java/reflection/recursive-method-used-to-find-all-classes-in-a-given-directory-and-sub.html
*
*/
public static Class<?>[] getClasses(String packageName) throws IOException
{
final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
assert classLoader != null;
if (debug)
{
System.out.println("Class Loader class is " + classLoader.getClass().getName());
}
final String packagePath = packageName.replace('.', '/');
final Enumeration<URL> resources = classLoader.getResources(packagePath);
final List<Class<?>> classes = new ArrayList<Class<?>>();
while (resources.hasMoreElements())
{
final URL resource = resources.nextElement();
final String proto = resource.getProtocol();
if ("file".equals(proto))
{
classes.addAll(findFileClasses(new File(resource.getFile()), packageName));
}
else if ("jar".equals(proto))
{
classes.addAll(findJarClasses(resource));
}
else
{
System.err.println("Protocol " + proto + " not supported");
continue;
}
}
return classes.toArray(new Class[classes.size()]);
}
/**
* Linear search for classes of a package from a jar file
*
* @param packageResource
* [in] Jar URL of the base package, i.e. file URL bested in jar URL
*
* @return The classes of package /packageResource/ and nested packages
*
* @throws -
*
* @author amicngh, Sam Ginrich@stackoverflow.com
*/
private static List<Class<?>> findJarClasses(URL packageResource)
{
final List<Class<?>> classes = new ArrayList<Class<?>>();
try
{
System.out.println("Jar URL Path is " + packageResource.getPath());
final URL fileUrl = new URL(packageResource.getPath());
final String proto = fileUrl.getProtocol();
if ("file".equals(proto))
{
final String filePath = fileUrl.getPath().substring(1); // skip leading /
final int jarTagPos = filePath.indexOf(".jar!/");
if (jarTagPos < 0)
{
System.err.println("Non-conformant jar file reference " + filePath + " !");
}
else
{
final String packagePath = filePath.substring(jarTagPos + 6);
final String jarFilename = filePath.substring(0, jarTagPos + 4);
if (debug)
{
System.out.println("Package " + packagePath);
System.out.println("Jar file " + jarFilename);
}
final String packagePrefix = packagePath + '/';
try
{
final JarInputStream jarFile = new JarInputStream(
new FileInputStream(jarFilename));
JarEntry jarEntry;
while (true)
{
jarEntry = jarFile.getNextJarEntry();
if (jarEntry == null)
{
break;
}
final String classPath = jarEntry.getName();
if (classPath.startsWith(packagePrefix) && classPath.endsWith(".class"))
{
final String className = classPath
.substring(0, classPath.length() - 6).replace('/', '.');
if (debug)
{
System.out.println("Found entry " + jarEntry.getName());
}
try
{
classes.add(Class.forName(className));
}
catch (final ClassNotFoundException x)
{
System.err.println("Cannot load class " + className);
}
}
}
jarFile.close();
}
catch (final Exception e)
{
e.printStackTrace();
}
}
}
else
{
System.err.println("Nested protocol " + proto + " not supprted!");
}
}
catch (final MalformedURLException e)
{
e.printStackTrace();
}
return classes;
}
/**
* Recursive method used to find all classes in a given directory and subdirs.
*
* @param directory
* The base directory
* @param packageName
* The package name for classes found inside the base directory
* @return The classes
* @author http://www.java2s.com/example/java/reflection/recursive-method-used-to-find-all-classes-in-a-given-directory-and-sub.html
* @throws -
*
*/
private static List<Class<?>> findFileClasses(File directory, String packageName)
{
final List<Class<?>> classes = new ArrayList<Class<?>>();
if (!directory.exists())
{
System.err.println("Directory " + directory.getAbsolutePath() + " does not exist.");
return classes;
}
final File[] files = directory.listFiles();
if (debug)
{
System.out.println("Directory "
+ directory.getAbsolutePath()
+ " has "
+ files.length
+ " elements.");
}
for (final File file : files)
{
if (file.isDirectory())
{
assert !file.getName().contains(".");
classes.addAll(findFileClasses(file, packageName + "." + file.getName()));
}
else if (file.getName().endsWith(".class"))
{
final String className = packageName
+ '.'
+ file.getName().substring(0, file.getName().length() - 6);
try
{
classes.add(Class.forName(className));
}
catch (final ClassNotFoundException cnf)
{
System.err.println("Cannot load class " + className);
}
}
}
return classes;
}
}
//从基于文件的类存储库中检索包及其嵌套包的类
电子稳定控制系统包;
导入java.io.File;
导入java.io.FileInputStream;
导入java.io.IOException;
导入java.net.MalformedURLException;
导入java.net.URL;
导入java.util.ArrayList;
导入java.util.Enumeration;
导入java.util.List;
导入java.util.jar.JarEntry;
导入java.util.jar.JarInputStream;
公共类GetClasses
{
私有静态布尔调试=false;
/**
*使用假定的包esc.util测试函数
*/
公共静态void main(字符串…参数)
{
尝试
{
最终类[]列表=getClasses(“esc.util”);
对于(最终c类:列表)
{
System.out.println(c.getName());
}
}
捕获(最终IOE例外)
{
e、 printStackTrace();
}
}
/**
*扫描可从上下文类加载器访问的属于给定包和子包的所有类。
*
*@Premission线程类加载器以独占方式吸引类和jar文件
*@带有静态代码段的前提条件类在加载时执行,因此不能引发异常
*
*@param packageName
*[in]基本包路径,点分隔
*
*@返回package/packageName/和嵌套包的类
*
*@IOException,
*ClassNotFoundException不适用
*
*@作者山姆·金里奇,http://www.java2s.com/example/java/reflection/recursive-method-used-to-find-all-classes-in-a-given-directory-and-sub.html
*
*/
公共静态类[]getClasses(字符串packageName)引发IOException
{
final ClassLoader ClassLoader=Thread.currentThread().getContextClassLoader();
断言类加载器!=null;
如果(调试)
{
System.out.println(“类加载器类为”+classLoader.getClass().getName());
}
最终字符串packagePath=packageName.replace('.','/');
最终枚举资源=classLoader.getResources(packagePath);
最终名单>();
while(resources.hasMoreElements())
{
最终URL资源=resources.nextElement();
最后一个字符串proto=resource.getProtocol();
如果(“文件”.equals(proto))
{
addAll(findFileClass(新文件(resource.getFile()),packageName));
}
else如果(“jar”.equals(proto))
{
addAll(findJarClasses(资源));
}
其他的
{
System.err.println(“协议”+协议+“不支持”);
继续;
}
}
返回classes.toArray(新类[classes.size()]);
}
/**
*从jar文件中线性搜索包的类
*
*@param-packageResource
*基本包的[in]Jar URL,即Jar URL中最好的文件URL
*
*@返回package/packageResource/和嵌套包的类
*
*@投掷-
*
*@作者阿明,山姆Ginrich@stackoverflow.com
*/
私有静态列表>类=新ArrayList>FindFileClass(文件目录,字符串packageName)
{
最终名单>();
如果(!directory.exists())
{
System.err.println(“目录”+目录.getAbsolutePath()+“不存在”);
返回类;
}
最终文件[]文件=目录.listFiles();
如果(调试)
{
System.out.println(“目录”
+directory.getAbsolutePath()
+“有”
+文件长度
// Retrieve classes of a package and it's nested package from file based class repository
package esc;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
public class GetClasses
{
private static boolean debug = false;
/**
* test function with assumed package esc.util
*/
public static void main(String... args)
{
try
{
final Class<?>[] list = getClasses("esc.util");
for (final Class<?> c : list)
{
System.out.println(c.getName());
}
}
catch (final IOException e)
{
e.printStackTrace();
}
}
/**
* Scans all classes accessible from the context class loader which belong to the given package and subpackages.
*
* @precondition Thread Class loader attracts class and jar files, exclusively
* @precondition Classes with static code sections are executed, when loaded and thus must not throw exceptions
*
* @param packageName
* [in] The base package path, dot-separated
*
* @return The classes of package /packageName/ and nested packages
*
* @throws IOException,
* ClassNotFoundException not applicable
*
* @author Sam Ginrich, http://www.java2s.com/example/java/reflection/recursive-method-used-to-find-all-classes-in-a-given-directory-and-sub.html
*
*/
public static Class<?>[] getClasses(String packageName) throws IOException
{
final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
assert classLoader != null;
if (debug)
{
System.out.println("Class Loader class is " + classLoader.getClass().getName());
}
final String packagePath = packageName.replace('.', '/');
final Enumeration<URL> resources = classLoader.getResources(packagePath);
final List<Class<?>> classes = new ArrayList<Class<?>>();
while (resources.hasMoreElements())
{
final URL resource = resources.nextElement();
final String proto = resource.getProtocol();
if ("file".equals(proto))
{
classes.addAll(findFileClasses(new File(resource.getFile()), packageName));
}
else if ("jar".equals(proto))
{
classes.addAll(findJarClasses(resource));
}
else
{
System.err.println("Protocol " + proto + " not supported");
continue;
}
}
return classes.toArray(new Class[classes.size()]);
}
/**
* Linear search for classes of a package from a jar file
*
* @param packageResource
* [in] Jar URL of the base package, i.e. file URL bested in jar URL
*
* @return The classes of package /packageResource/ and nested packages
*
* @throws -
*
* @author amicngh, Sam Ginrich@stackoverflow.com
*/
private static List<Class<?>> findJarClasses(URL packageResource)
{
final List<Class<?>> classes = new ArrayList<Class<?>>();
try
{
System.out.println("Jar URL Path is " + packageResource.getPath());
final URL fileUrl = new URL(packageResource.getPath());
final String proto = fileUrl.getProtocol();
if ("file".equals(proto))
{
final String filePath = fileUrl.getPath().substring(1); // skip leading /
final int jarTagPos = filePath.indexOf(".jar!/");
if (jarTagPos < 0)
{
System.err.println("Non-conformant jar file reference " + filePath + " !");
}
else
{
final String packagePath = filePath.substring(jarTagPos + 6);
final String jarFilename = filePath.substring(0, jarTagPos + 4);
if (debug)
{
System.out.println("Package " + packagePath);
System.out.println("Jar file " + jarFilename);
}
final String packagePrefix = packagePath + '/';
try
{
final JarInputStream jarFile = new JarInputStream(
new FileInputStream(jarFilename));
JarEntry jarEntry;
while (true)
{
jarEntry = jarFile.getNextJarEntry();
if (jarEntry == null)
{
break;
}
final String classPath = jarEntry.getName();
if (classPath.startsWith(packagePrefix) && classPath.endsWith(".class"))
{
final String className = classPath
.substring(0, classPath.length() - 6).replace('/', '.');
if (debug)
{
System.out.println("Found entry " + jarEntry.getName());
}
try
{
classes.add(Class.forName(className));
}
catch (final ClassNotFoundException x)
{
System.err.println("Cannot load class " + className);
}
}
}
jarFile.close();
}
catch (final Exception e)
{
e.printStackTrace();
}
}
}
else
{
System.err.println("Nested protocol " + proto + " not supprted!");
}
}
catch (final MalformedURLException e)
{
e.printStackTrace();
}
return classes;
}
/**
* Recursive method used to find all classes in a given directory and subdirs.
*
* @param directory
* The base directory
* @param packageName
* The package name for classes found inside the base directory
* @return The classes
* @author http://www.java2s.com/example/java/reflection/recursive-method-used-to-find-all-classes-in-a-given-directory-and-sub.html
* @throws -
*
*/
private static List<Class<?>> findFileClasses(File directory, String packageName)
{
final List<Class<?>> classes = new ArrayList<Class<?>>();
if (!directory.exists())
{
System.err.println("Directory " + directory.getAbsolutePath() + " does not exist.");
return classes;
}
final File[] files = directory.listFiles();
if (debug)
{
System.out.println("Directory "
+ directory.getAbsolutePath()
+ " has "
+ files.length
+ " elements.");
}
for (final File file : files)
{
if (file.isDirectory())
{
assert !file.getName().contains(".");
classes.addAll(findFileClasses(file, packageName + "." + file.getName()));
}
else if (file.getName().endsWith(".class"))
{
final String className = packageName
+ '.'
+ file.getName().substring(0, file.getName().length() - 6);
try
{
classes.add(Class.forName(className));
}
catch (final ClassNotFoundException cnf)
{
System.err.println("Cannot load class " + className);
}
}
}
return classes;
}
}