扫描Java类路径以查找单独的子类?

扫描Java类路径以查找单独的子类?,java,reflection,classpath,classloader,war,Java,Reflection,Classpath,Classloader,War,我有一个非常独特的情况,我知道我的Java web应用程序总是打包在一个AbstractWidget的1个且仅1个具体子类中: public abstract class AbstractWidget { // ... } public class SimpleWidget extends AbstractWidget { // ... } public class ComplexWidget extends AbstractWidget { // ... } pu

我有一个非常独特的情况,我知道我的Java web应用程序总是打包在一个
AbstractWidget
的1个且仅1个具体子类中:

public abstract class AbstractWidget {
    // ...
}

public class SimpleWidget extends AbstractWidget {
    // ...
}

public class ComplexWidget extends AbstractWidget {
    // ...
}

public class CrazyComplexWidget extends AbstractWidget {
    // ...
}

// ...etc.
同样,我知道在运行时,我的
WAR/WEB-INF/classes
目录将始终包含一个且仅一个
AbstractWidget
impl包(不多也不少),无论是
ComplexWidget.class
SimpleWidget.class
,等等

我正在尝试构造代码(当WAR从其
ServletContextListener
impl内部启动时实际运行),该代码能够扫描运行时类路径并获得
AbstractWidget
的实例(使用public no arg构造函数

因此,如果我的战争:

myWar/
    WEB-INF/
        lib/
        classes/
            com/
                myorg/
                    App (implements ServletContextListener)
                    ... lots of other classes and packages
                    some/
                        arbitrary/
                            package/
                                SimpleWidget
然后,从
App#contextInitialized(ServletContextEvent)
内部,我需要在类路径上找到
SimpleWidget.class
的代码,并给我一个实例:

public class App implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent event) {
        // Scan classpath for the lone AbstractWidget impl somehow.
        ???

        // Use public, no-arg ctor to instantiate the impl.
        AbstractWidget widget = ???

        // Now do stuff with widget...
    }
}

我知道您可以使用反射方法,如
Class.isAssignableFrom()
,但不确定这是否是正确的方法,即使是正确的方法,也不确定如何在给定的用例中使用它。有什么想法吗?提前谢谢

您可能想检查一下它是否有用于查找给定类的子类的实用程序。你可以用它做类似的事情:

Reflections reflections = new Reflections();
Set<Class<? extends AbstractWidget>> subclasses;
subclasses = reflections.getSubTypesOf(AbstractWidget.class);
反射=新反射();

Set我知道这是一个非常古老的问题,但是类图库可以帮助您非常容易地获得类路径中的所有类,扩展给定类,基本上是给定类的所有子类

梯度依赖

compile group: 'io.github.classgraph', name: 'classgraph', version: '4.8.46'
这是如何轻松地扫描类路径的

ScanResult scanResult = new ClassGraph()
    .whitelistPackages("com.myorg") //whatever package you want to scan
    .verbose()
    .enableAllInfo() 
    .scan();

System.out.println("Classes which extending '" + AbstractWidget.class.getSimpleName() + "' class");
ClassInfoList classInfoList = scanResult.getSubclasses(AbstractWidget.class.getName());
for (ClassInfo classInfo : classInfoList) {
    System.out.println("\t" + classInfo.getName());
}
Classes which extending 'AbstractWidget' class
    com.myorg.some.arbitrary.package.SimpleWidget
假设类路径中有SimpleWidget类,则输出

ScanResult scanResult = new ClassGraph()
    .whitelistPackages("com.myorg") //whatever package you want to scan
    .verbose()
    .enableAllInfo() 
    .scan();

System.out.println("Classes which extending '" + AbstractWidget.class.getSimpleName() + "' class");
ClassInfoList classInfoList = scanResult.getSubclasses(AbstractWidget.class.getName());
for (ClassInfo classInfo : classInfoList) {
    System.out.println("\t" + classInfo.getName());
}
Classes which extending 'AbstractWidget' class
    com.myorg.some.arbitrary.package.SimpleWidget

我希望有帮助。ClassGraph是一个非常强大的库,可以满足这个简单的需求。这篇文章解释得很好

你事先知道子类的名称吗?谢谢@Joni(+1)-不,这是我的问题。我需要一种方法来描述一个扩展
AbstractWidget
的类并搜索它。同样,这些类中只有一个。我想我可能不得不求助于注释,但如果我能避免它们,我更愿意。你怎么知道只有一个,它是否包含在外部进程中?同一个进程可以在配置文件中添加子类的名称吗?再次感谢@Joni(+1)-是的,外部进程打包了WAR(并保证在类路径中的某个地方只包含1个子类)。是的,这个外部进程可能包含一个带有子类名称的配置文件,但这将是非常痛苦的(外部进程是一个遗留系统,我们不再有它的源代码)。所以我不想去探索这个选项,除非它真的是我唯一的解决方案。