天道酬勤,学无止境

Reflectively get all packages in a project?

How can I reflectively get all of the packages in the project? I started with Package.getPackages(), but that only got all the packages associated to the current package. Is there a way to do this?

评论

@PhilippWendler's comment led me to a method of accomplishing what I needed. I tweaked the method a little to make it recursive.

    /**
     * Recursively fetches a list of all the classes in a given
     * directory (and sub-directories) that have the @UnitTestable
     * annotation.
     * @param packageName The top level package to search.
     * @param loader The class loader to use. May be null; we'll
     * just grab the current threads.
     * @return The list of all @UnitTestable classes.
     */
    public List<Class<?>> getTestableClasses(String packageName, ClassLoader loader) {
        // State what package we are exploring
        System.out.println("Exploring package: " + packageName);
        // Create the list that will hold the testable classes
        List<Class<?>> ret = new ArrayList<Class<?>>();
        // Create the list of immediately accessible directories
        List<File> directories = new ArrayList<File>();
        // If we don't have a class loader, get one.
        if (loader == null)
            loader = Thread.currentThread().getContextClassLoader();
        // Convert the package path to file path
        String path = packageName.replace('.', '/');
        // Try to get all of nested directories.
        try {
            // Get all of the resources for the given path
            Enumeration<URL> res = loader.getResources(path);
            // While we have directories to look at, recursively
            // get all their classes.
            while (res.hasMoreElements()) {
                // Get the file path the the directory
                String dirPath = URLDecoder.decode(res.nextElement()
                        .getPath(), "UTF-8");
                // Make a file handler for easy managing
                File dir = new File(dirPath);
                // Check every file in the directory, if it's a
                // directory, recursively add its viable files
                for (File file : dir.listFiles()) {
                    if (file.isDirectory()) 
                        ret.addAll(getTestableClasses(packageName + '.' + file.getName(), loader));
                }
            }
        } catch (IOException e) {
            // We failed to get any nested directories. State
            // so and continue; this directory may still have
            // some UnitTestable classes.
            System.out.println("Failed to load resources for [" + packageName + ']');
        }
        // We need access to our directory, so we can pull
        // all the classes.
        URL tmp = loader.getResource(path);
        System.out.println(tmp);
        if (tmp == null)
            return ret;
        File currDir = new File(tmp.getPath());
        // Now we iterate through all of the classes we find
        for (String classFile : currDir.list()) {
            // Ensure that we only find class files; can't load gif's!
            if (classFile.endsWith(".class")) {
                // Attempt to load the class or state the issue
                try {
                    // Try loading the class
                    Class<?> add = Class.forName(packageName + '.' +
                            classFile.substring(0, classFile.length() - 6));
                    // If the class has the correct annotation, add it
                    if (add.isAnnotationPresent(UnitTestable.class))
                        ret.add(add);
                    else 
                        System.out.println(add.getName() + " is not a UnitTestable class");
                } catch (NoClassDefFoundError e) {
                    // The class loader could not load the class
                    System.out.println("We have found class [" + classFile + "], and couldn't load it.");
                } catch (ClassNotFoundException e) {
                    // We couldn't even find the damn class
                    System.out.println("We could not find class [" + classFile + ']');
                }
            }
        }
        return ret;
    }

It's possible but tricky and expensive, since you need to walk the classpath yourself. Here is how TestNG does it, you can probably extract the important part for yourself:

https://github.com/cbeust/testng/blob/master/src/main/java/org/testng/internal/PackageUtils.java

This approach prints all packages only (at least a root "packageName" has to be given first).

It is derived from above.

package devTools;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

public class DevToolUtil {

    /**
     * Method prints all packages (at least a root "packageName" has to be given first).
     *
     * @see http://stackoverflow.com/questions/9316726/reflectively-get-all-packages-in-a-project
     * @since 2016-12-05
     * @param packageName
     * @param loader
     * @return List of classes.
     */
    public List<Class<?>> getTestableClasses(final String packageName, ClassLoader loader) {
        System.out.println("Exploring package: " + packageName);

        final List<Class<?>> ret = new ArrayList<Class<?>>();

        if (loader == null) {
            loader = Thread.currentThread().getContextClassLoader();
        }

        final String path = packageName.replace('.', '/');

        try {
            final Enumeration<URL> res = loader.getResources(path);

            while (res.hasMoreElements()) {
                final String dirPath = URLDecoder.decode(res.nextElement().getPath(), "UTF-8");
                final File dir = new File(dirPath);

                if (dir.listFiles() != null) {
                    for (final File file : dir.listFiles()) {
                        if (file.isDirectory()) {
                            final String packageNameAndFile = packageName + '.' + file.getName();
                            ret.addAll(getTestableClasses(packageNameAndFile, loader));
                        }
                    }
                }
            }
        } catch (final IOException e) {
            System.out.println("Failed to load resources for [" + packageName + ']');
        }

        return ret;
    }

    public static void main(final String[] args) {
        new DevToolUtil().getTestableClasses("at", null);
    }
}

May be off-topic (because it is not exactly in terms of java "reflection") ... However, how about the following solution:

Java packages can be treated as folders (or directories on Linux\UNIX). Assuming that you have a root package and its absolute path is known, you can recursively print all sub-folders that have *.java or *.class files using the following batch as the basis:

@echo off
rem List all the subfolders under current dir

FOR /R "." %%G in (.) DO (
 Pushd %%G
 Echo now in %%G
 Popd )
Echo "back home" 

You can wrap this batch in java or if you run on Linux\Unix rewrite it in some shell script.

Good Luck!

Aviad.

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 仅靠简单名称来反思地找到一个类(Finding a class reflectively by its simple-name alone)
    问题 我想知道是否有任何给定的函数可以让我自省一个类,而不必编写包含该类的包。 例如,我想看一看Integer类的方法和超类,为此我必须指定该类所在的包。 这将是“ java.lang.Integer” 而不是这样做,我只想键入类名称以显示该类的信息。 就像这个“整数” 不管程序位于何处,如何使我的程序仅检查类名? 回答1 Java不会阻止您创建自己的my.company.Integer类和my.other.company.Integer类,因此它无法知道哪个Integer类是正确的类。 我建议的答案最接近的是创建一个预定义的软件包列表,在其中您要搜索该类,并继续尝试每个软件包,直到找到您的类为止。 所以像这样: class ClassFinder{ public static final String[] searchPackages = { "java.lang", "java.util", "my.company", "my.company.other" }; public Class<?> findClassByName(String name) { for(int i=0; i<searchPackages.length; i++){ try{ return Class.forName(searchPackages[i] + "." + name); } catch
  • Finding a class reflectively by its simple-name alone
    I was wondering if there is any given function that allows me to introspect a class without having to write the packages where the class is contained. For example, I want to take a look at the methods and superclasses of the class Integer in order to do that I have to specify the packages where the class is located. This will be "java.lang.Integer" Instead of doing that I want to just type the class name in order to have the information of the class displayed. Just like this "Integer" How can I make that my program just check the class name, no matter where is it located?
  • 如何以反射方式调用Java 8默认方法(How do I invoke Java 8 default methods reflectively)
    问题 给定这个简单的“ Hello World”式Java 8接口,如何通过反射调用其hello()方法? public interface Hello { default String hello() { return "Hello"; } } 回答1 您可以为此使用MethodHandles: import java.lang.invoke.MethodHandles; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ReflectiveDefaultMethodCallExample { static interface Hello { default String hello() { return "Hello"; } } public static void main(String[] args) throws Throwable{ Hello target = //new Hello(){}; (Hello)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),new Class[]{Hello.class}, (Object proxy, Method method
  • 在 Java 中可以“反射性地”访问方法的源代码吗?(It's possible in Java to access the source code of a method “reflectively”?)
    问题 恐怕答案是否定的,但也许你们中的一个让我感到惊讶。 谢谢。 编辑 1:我知道这个问题没有多大意义,但我认为这一点已被理解,遗憾的是,答案是否定的。 无论如何,我更改了问题的标题,为“反射性”一词添加了引号,以防万一,我将尝试更好地解释我的意图。 我有一个类型的实例,它是某个抽象类型的子类,它有一些已知的方法。 我想在运行时获取一个字符串,其中包含实例类型中此类方法之一的实际实现的源代码。 我认为值得指出的是,实例的实际类型可能是一个匿名的内部类......此外,源代码的“反编译”版本就足够了。 我想获取源码的方法,大部分时候只有一行.... 谢谢。 回答1 正如其他人指出的那样:没有。 您可以像 JVM 一样访问类的对象、其方法等。 这是唯一可能的,因为每个类在编译时都存储有关其自身及其成员的信息。 如果我不得不猜测,这发生在继承树中的根对象 Object 中。 您可以使用反编译器反编译类文件,然后使用该反编译器进行检查。 但是您不能像 String 或任何类似的东西一样访问源代码。 想一想:如果您为 JVM 编译了 Scala 代码,那么您也无法取回 Scala 代码。 而且您无法获得java代码。 你有什么特别的理由想要这样做吗? 是否有任何其他方法可以尝试实现您的目标,无论它是什么? 问候 回答2 我不这么认为。 当.java被编译时,它变成了一个.class ;
  • 如何在Java中遍历Class属性?(How to loop over a Class attributes in Java?)
    问题 如何动态遍历Java中的类属性。 例如: public class MyClass{ private type1 att1; private type2 att2; ... public void function(){ for(var in MyClass.Attributes){ System.out.println(var.class); } } } Java有可能吗? 回答1 没有语言支持可满足您的要求。 您可以在运行时使用反射来反射地访问类型的成员(例如,使用Class.getDeclaredFields()获得Field数组),但是根据您要执行的操作,这可能不是最佳解决方案。 也可以看看 Java教程:反射API /高级语言主题:反射 相关问题 什么是反射,为什么有用? Java思考:为什么这么糟? 反射如何不会导致代码异味? 转储Java对象的属性 例子 这是一个简单的示例,仅显示反射功能的一部分。 import java.lang.reflect.*; public class DumpFields { public static void main(String[] args) { inspect(String.class); } static <T> void inspect(Class<T> klazz) { Field[] fields = klazz
  • can I reflectively instantiate a generic type in java?
    Is it possible to reflectively instantiate a generic type in Java? Using the technique described here I get an error because class tokens cannot be generic. Take the example below. I want to instantiate some subclass of Creator that implements Creator. The actual class name is passed in as a command line argument. The idea is to be able to specify an implementation of Creator at runtime. Is there another way to accomplish what I'm trying to do here? public interface Creator<T> { T create(); } public class StringCreator implements Creator<String> { public String create() { return new String();
  • 如何反射打印方法主体?(How do I print the method body reflectively?)
    问题 现在我有 private static void getMethods(Class<? extends Object> clazz) { Method[] declaredMethods = clazz.getDeclaredMethods(); for (Method aMethod : declaredMethods) { aMethod.setAccessible(true); // Print the declaration System.out.print(Modifier.toString(aMethod.getModifiers()) + " " + aMethod.getReturnType().getSimpleName() + " " + aMethod.getName()); // Get Parameter Types getParameters(aMethod); //Empty Body System.out.println("{}\n"); } } 它反射性地打印大多数信息,但会创建一个空的正文。 如何增加Java的反射性来打印方法主体? 回答1 如何增加Java的反射性来打印方法主体? 恐怕很难。 首先,原始源代码很可能对正在运行的程序不可用。 通常,开发人员不要在二进制JAR中包含源代码。 (即使这样做,也不能保证它们将成为“真实”来源。)
  • Scala:从字段名称中反射性地设置字段值(Scala: set a field value reflectively from field name)
    问题 我正在学习scala,无法找到如何执行此操作的方法: 我在scala对象和google appengine实体之间做一个映射器,所以如果我有一个像这样的类: class Student { var id:Long var name:String } 我需要创建该类的实例,在java中,我会通过其名称获取Field,然后执行field.set(object, value)但是我无法在scala中找到方法。 我不能使用Java反射,因为Student的字段被视为私有字段,因此field.set引发错误。 谢谢 回答1 Scala将“ var”变成一个私有字段,一个getter和一个setter。 因此,为了通过使用String标识它来获取/设置var,您需要使用Java反射来找到getter / setter方法。 下面是执行此操作的代码段。 请注意,此代码在Scala 2.8.0下运行,并且不存在重复方法名称和错误的处理。 class Student { var id: Long = _ var name: String = _ } implicit def reflector(ref: AnyRef) = new { def getV(name: String): Any = ref.getClass.getMethods.find(_.getName == name)
  • How do I reflectively invoke a method with null as argument?
    I am trying to invoke this method in Java reflectively: public void setFoo(ArrayList<String> foo) { this.foo = foo; } The problem is that I want to pass null as null, so that foo becomes null. However, in the following approach it assumes that there are no arguments, and I get IllegalArgumentException(wrong number of arguments): method.invoke(new FooHolder(), null); // -----------------------------^ - I want null to be passed to the method... How is this accomplished?
  • 如何反思地调用以null为参数的方法?(How do I reflectively invoke a method with null as argument?)
    问题 我试图以反射方式在Java中调用此方法: public void setFoo(ArrayList<String> foo) { this.foo = foo; } 问题是我想将null传递为null ,以便foo变为null。 但是,在以下方法中,它假定没有参数,并且我得到IllegalArgumentException ( wrong number of arguments ): method.invoke(new FooHolder(), null); // -----------------------------^ - I want null to be passed to the method... 这是如何完成的? 回答1 尝试 method.invoke(new FooHolder(), new Object[]{ null }); 回答2 编译器警告应使您意识到该问题。 类型为null的参数应显式转换为Object [],以从类型Method调用varargs方法invoke(Object,Object ...)。 也可以将其强制转换为Object以进行varargs调用 您可以像这样修复它; Object arg = null; method.invoke(new FooHolder(), arg); 回答3 对我来说,这不起作用: m.invoke(c
  • Scala:如何动态实例化对象并使用反射调用方法?(Scala: How do I dynamically instantiate an object and invoke a method using reflection?)
    问题 在Scala中,动态实例化对象并使用反射调用方法的最佳方法是什么? 我想做以下Java代码的Scala等效项: Class class = Class.forName("Foo"); Object foo = class.newInstance(); Method method = class.getMethod("hello", null); method.invoke(foo, null); 在上面的代码中,类名和方法名都是动态传递的。 上面的Java机制很可能用于Foo和hello() ,但是Scala类型与Java并不一对一匹配。 例如,可以为单例对象隐式声明一个类。 Scala方法还允许使用各种符号作为其名称。 两者都通过名称修改解决。 请参阅Java和Scala之间的互操作。 另一个问题似乎是通过解决重载和自动装箱来实现参数的匹配,如《 Scala的思考-天堂与地狱》中所述。 回答1 有一种更简单的方法来反射地调用方法,而不必诉诸Java反射方法:使用结构化键入。 只需将对象引用转换为具有必要方法签名的“结构类型”,然后调用该方法:不需要反射(当然,Scala在下面进行反射,但我们不需要这样做)。 class Foo { def hello(name: String): String = "Hello there, %s".format(name) }
  • 可以反射地实例化Java中的泛型类型吗?(can I reflectively instantiate a generic type in java?)
    问题 是否可以反射性地实例化Java中的泛型类型? 使用此处描述的技术,由于类标记不能通用,我会遇到错误。 请看下面的例子。 我想实例化一些实现Creator的Creator子类。 实际的类名称作为命令行参数传递。 这个想法是为了能够在运行时指定Creator的实现。 还有另一种方法可以完成我在这里要做的事情吗? public interface Creator<T> { T create(); } public class StringCreator implements Creator<String> { public String create() { return new String(); } } public class FancyStringCreator implements Creator<String> { public String create() { return new StringBuffer().toString(); } } public static void main(String[] args) throws Exception { Class<?> someClass = Class.forName(args[0]); /*ERROR*/Class<? extends Creator<String>> creatorClass =
  • Scala: set a field value reflectively from field name
    I'm learning scala and can't find out how to do this: I'm doing a mapper between scala objects and google appengine entities, so if i have a class like this: class Student { var id:Long var name:String } I need to create an instance of that class, in java i would get the Field by it's name and then do field.set(object, value) but I can't find how to do so in scala. I can't use java reflection since the fields of Student are seen as private and field.set throws an error because of that. Thanks
  • Eclipse - JAR creation failed “Class files on classpath not found or not accessible for…”
    I have a project in Eclipse that has a red cross on it and will not export to a runnable JAR. I can't remember if I have looked at it since I reinstalled Windows on my laptop, but I know that I haven't changed any code. There are no errors in any of the classes, however the error I get points to the following class that deals with the menu items on Mac OSx: import java.lang.reflect.*; public class osxhandler implements InvocationHandler { protected Object targetObject; protected Method targetMethod; protected String proxySignature; static Object macOSXApplication; // Pass this method an Object
  • How do I print the method body reflectively?
    Right now I have private static void getMethods(Class<? extends Object> clazz) { Method[] declaredMethods = clazz.getDeclaredMethods(); for (Method aMethod : declaredMethods) { aMethod.setAccessible(true); // Print the declaration System.out.print(Modifier.toString(aMethod.getModifiers()) + " " + aMethod.getReturnType().getSimpleName() + " " + aMethod.getName()); // Get Parameter Types getParameters(aMethod); //Empty Body System.out.println("{}\n"); } } Which prints most information reflectively but creates an empty body. How do I add to the reflective nature of Java to print the method body?
  • Implementing Generic Type Inference in C# reflectively
    I need to do some generic type inference for a scripting language implementation and I am wondering if I am missing some straightforward approach. For the moment let me just ask about type structure and ignore bounds. To illustrate, here is a deeply nested example: T foo<T>( List<List<List<T>>> ) {...} Now I want to test if I can pass an argument bar of type: List<List<List<string>>> to that method and later use MakeGenericMethod() with the discovered param type to reify and invoke it. From what I can tell, even if I manage to construct an open generic type equivalent to the foo argument (i.e
  • 减少jar文件大小(Reduce jar file size)
    问题 有没有办法减少jar文件的大小? 我想要一个减少未使用依赖项的工具。 我使用 maven 进行依赖管理。 回答1 JAR 文件通常不包含 Maven 意义上的依赖项。 所以你一定是在说: WAR 或 EAR 或类似文件, 通过组合大量JAR文件产生的所谓UberJAR文件; 例如使用Maven shade插件,或比 Maven 模块更精细的依赖关系。 在前两种情况下,您可以通过在依赖项规范或 war 或 shade 插件构建描述符中排除它们来排除名义上的依赖 JAR。 IIRC,shade 插件还允许您排除特定的包和类。 最后一个可能需要一个单独的工具来对 JAR 文件进行后处理。 摆脱未使用的类是混淆器可以做的事情。 但是,您需要注意不要消除反射性使用的类或类名; 例如通过 DI / IoC 框架或 AOP 框架。 (一般来说,这种工具试图通过分析.class文件外部引用隐含的依赖来弄清楚使用了哪些类。DI/IoC/AOP等引入了.class文件中不明显的其他种类的依赖结构体。) 回答2 如果您想知道您的项目使用的依赖项,只需检查 maven-dependency-plugin 可用于分析使用/未使用的依赖项。 通过以下方式检查您的依赖项: mvn dependency:analyze 或者像这样查看 dep 树: mvn dependency:tree 或者
  • How do I invoke Java 8 default methods reflectively
    Given this simple "Hello World"ish Java 8 interface, how do I invoke its hello() method via reflection? public interface Hello { default String hello() { return "Hello"; } }
  • Android Dagger 依赖注入在私有字段上失败(Android Dagger Dependency Injection fails on private Fields)
    问题 我是 dagger 的新手(尽管我有使用 Weld 处理 Java EE WebApps 的 DI 经验)。 我想要做的是将依赖项注入到一个类中。 该领域是私人的。 Dagger 然后抛出一个异常,说明它不能注入私有字段。 这是什么原因? 毕竟可以使用反射写入私有字段,即使在 android.. 如果我将字段的可见性设置为私有以外的其他内容,则注入似乎有效。 回答1 使私有字段“包可见”可能并不总是您想要的。 Dagger 文档建议如下: 注入 final 字段和私有成员。 为了获得最佳性能,Dagger 会生成代码。 通过使用构造函数注入来解决这个问题。 下面是一个例子: private ItemFactoryImpl itemFactory; private BuildingFactory buildingFactory; @Inject public World(ItemFactoryImpl itemFactory, BuildingFactory buildingFactory) { this.itemFactory = itemFactory; this.buildingFactory = buildingFactory; } 回答2 Dagger 无法支持私有字段,但仍支持代码生成的适配器(以避免反射)。 像 Guice
  • 在多个平台中注册 URL 协议处理程序(Registering a URL protocol handler in a multiple platforms)
    问题 我想创建一个安装在多个平台(Windows、Mac OS、Linux)上的 Java 应用程序作为此安装的一部分我想注册一个 URL 协议处理程序,以便在单击链接时加载我的应用程序。 即我想要这样的东西:myprotocol://example.com 有没有一种统一的方式来做到这一点? 或者某种可以推断不同操作系统之间差异的框架。 回答1 MultiBit 在一系列平台上实现了这一点 我刚刚在 MultiBit 项目(一个轻量级比特币客户端)的这条路上走下去,我必须实现启动和更新应用程序以响应自定义 URI(在我的例子中bitcoin:1sdfjsdfdkfdkjfdjfkjertn?amount=0.5&label=Some%20Text )。 我必须实现它的方法是创建一个通用的方法来接收操作系统事件。 很多工作都是基于 Macify 库,然后重写以支持多个任意平台。 首先介绍一下背景。 通常,协议处理程序在操作系统端注册,而不是在浏览器端注册。 这是因为协议不限于浏览器,因此需要通用的支持机制。 因此,您需要为要支持的每个平台创建处理程序。 例如,在 Mac 世界中有 EAWT 库,该库不可用于分发,但提供对本机事件 API 的访问。 这意味着您的应用程序需要能够在运行时定位这个库,然后反射性地使用本机类(您不能对它们进行硬编码