在限制范围内获取所有 类
Get all classes within constrains
我正在尝试制作一个从 SQLite 数据库到我的项目逻辑层的通用实例映射器。
映射器中的每个条目都是一些 class “DAL< 名称 >” 的实例,例如 DALProduct
都在同一个包中,扩展 class DALObject
具有以下结构:
public abstract class DALObject{
abstract String getCreate();
... //other logic
}
使用反射,我可以轻松地在每个 class 上调用 getCreate
方法,并从中获得我需要的东西。
问题是我不知道有多少 child classes DALObject
并且我想要一个在添加新映射器时不需要触及的映射器。
我知道你可以得到所有 child class 的 DALObject
已经加载但是我 运行 这个代码在我的程序的最开始在我加载任何 classes.
之前
有什么想法吗?我有一个相当大的约束案例,所以也许我可以以某种方式将其组合在一起。
这将是何时使用注释的完美实例。您可以在每个 class 的声明之前定义注释,表明 class 有一些关于 'DALObjects' 的元数据。然后你可以使用 Reflections 或一些类似的库来轻松找到所有带有此注释的 Class 对象。
例如;
@Target(value=TYPE)
public @interface DALObject {
}
@DALObject
public class MyDALObject {
}
Reflections reflections = new Reflections(new ConfigurationBuilder()
.setScanners(new TypeAnnotationsScanner()));
Set<Class<?>> annotatedWithDALObject = reflections.getTypesAnnotatedWith(DALObject.class);
这样的任务只能通过扫描 class 路径上的每个 class 来实现(这取决于您使用的库数量,通常 很多 ) 并查看它是否扩展了 DALObject。
如果您想走那条路,org.reflections 库可以帮助您:
Reflections reflections = new Reflections("my.package",
Reflector.class.getClassLoader(), new SubTypesScanner(false));
Set<Class<? extends Module>> modules = reflections.getSubTypesOf(DALObject.class);
出于性能原因,我强烈建议在您的应用程序启动期间执行一次此扫描并存储结果。
作为一种替代方法(我在这里没有考虑Class
的泛型类型安全,这是要实现的):
public abstract class DALObject {
public static List<Class> subTypes = new ArrayList<>();
public DALObject() {
DALObject.subTypes.add(this.getClass());
}
}
显然这只有在你在某个地方实例化子classes的对象时才有效,如果你的getCreate
首先打算这样做,我的建议显然行不通。
据我所知,Reflections 没有得到很好的支持(多年来只有微小的变化)并且仍然 doesn't work with modules。
相反,我建议使用 ClassGraph,它得到了高度积极的维护,并且可以与模块、奇怪的 class 加载器和其他东西一起使用。
您会发现 DALObject
像这样的实现:
ScanResult scanResults = new ClassGraph()
.acceptPackages(packages) //skip to scan ALL packages
.enableAllInfo() //Not necessary but gives you more info to filter on, if needed
.initializeLoadedClasses()
.scan();
//You can cache, or serialize scanResults using scanResults.toJSON()
List<Class<?>> impls = scanResults.getAllClasses().stream()
.filter(impl -> impl.extendsSuperclass(DALObject.getName()))
// or impl.implementsInterface(DALObject.getName()) if DALObject is an interface
.flatMap(info -> info.loadClass()) //or load the class yourself if you need to customize the logic
.collect(Collectors.toList());
我正在尝试制作一个从 SQLite 数据库到我的项目逻辑层的通用实例映射器。
映射器中的每个条目都是一些 class “DAL< 名称 >” 的实例,例如 DALProduct
都在同一个包中,扩展 class DALObject
具有以下结构:
public abstract class DALObject{
abstract String getCreate();
... //other logic
}
使用反射,我可以轻松地在每个 class 上调用 getCreate
方法,并从中获得我需要的东西。
问题是我不知道有多少 child classes DALObject
并且我想要一个在添加新映射器时不需要触及的映射器。
我知道你可以得到所有 child class 的 DALObject
已经加载但是我 运行 这个代码在我的程序的最开始在我加载任何 classes.
有什么想法吗?我有一个相当大的约束案例,所以也许我可以以某种方式将其组合在一起。
这将是何时使用注释的完美实例。您可以在每个 class 的声明之前定义注释,表明 class 有一些关于 'DALObjects' 的元数据。然后你可以使用 Reflections 或一些类似的库来轻松找到所有带有此注释的 Class 对象。
例如;
@Target(value=TYPE)
public @interface DALObject {
}
@DALObject
public class MyDALObject {
}
Reflections reflections = new Reflections(new ConfigurationBuilder()
.setScanners(new TypeAnnotationsScanner()));
Set<Class<?>> annotatedWithDALObject = reflections.getTypesAnnotatedWith(DALObject.class);
这样的任务只能通过扫描 class 路径上的每个 class 来实现(这取决于您使用的库数量,通常 很多 ) 并查看它是否扩展了 DALObject。
如果您想走那条路,org.reflections 库可以帮助您:
Reflections reflections = new Reflections("my.package",
Reflector.class.getClassLoader(), new SubTypesScanner(false));
Set<Class<? extends Module>> modules = reflections.getSubTypesOf(DALObject.class);
出于性能原因,我强烈建议在您的应用程序启动期间执行一次此扫描并存储结果。
作为一种替代方法(我在这里没有考虑Class
的泛型类型安全,这是要实现的):
public abstract class DALObject {
public static List<Class> subTypes = new ArrayList<>();
public DALObject() {
DALObject.subTypes.add(this.getClass());
}
}
显然这只有在你在某个地方实例化子classes的对象时才有效,如果你的getCreate
首先打算这样做,我的建议显然行不通。
据我所知,Reflections 没有得到很好的支持(多年来只有微小的变化)并且仍然 doesn't work with modules。 相反,我建议使用 ClassGraph,它得到了高度积极的维护,并且可以与模块、奇怪的 class 加载器和其他东西一起使用。
您会发现 DALObject
像这样的实现:
ScanResult scanResults = new ClassGraph()
.acceptPackages(packages) //skip to scan ALL packages
.enableAllInfo() //Not necessary but gives you more info to filter on, if needed
.initializeLoadedClasses()
.scan();
//You can cache, or serialize scanResults using scanResults.toJSON()
List<Class<?>> impls = scanResults.getAllClasses().stream()
.filter(impl -> impl.extendsSuperclass(DALObject.getName()))
// or impl.implementsInterface(DALObject.getName()) if DALObject is an interface
.flatMap(info -> info.loadClass()) //or load the class yourself if you need to customize the logic
.collect(Collectors.toList());