如何将自定义字段注入添加到 FXMLLoader 的默认 ControllerFactory?

我想initialize在创建时自动调用控制器的方法之前在控制器中设置一些非 UI 字段。据我了解,这样做的方式是定制的提供ControllerFactory,因为initialize()被调用后 ControllerFactory返回创建的对象。我想根据这个答案使用以下代码:


FXMLLoader loader = new FXMLLoader(mainFXML); // some .fxml file to load

loader.setControllerFactory(param -> {

    Object controller = null;

    try {

        controller = ReflectUtil.newInstance(param); // this is default behaviour

    } catch (InstantiationException | IllegalAccessException e) {

        e.printStackTrace();

    }

    if (controller instanceof Swappable) {

        ((Swappable) controller).setSwapper(swapper); // this is what I want to add

    }

    return controller;

});

但是,ReflectUtil该类(在 default setControllerFactory method 中使用)是com.sun.reflect.misc包的一部分,我无法使用它,因为编译失败并带有error: package sun.reflect.misc does not exist.


据我了解,我不能使用 sun 包,因为这不是公共 API。所以问题是:我该怎么办?我找不到任何其他示例,只有带有 ReflectUtil 的示例,而且,我希望我ControllerFactory能够使用 @FXML 注释来遵守 JavaFX 的默认工作流等等,这是否可以与其他一些 DI 框架(如 Jodd Petite)一起使用,例如?还有其他方法可以设置字段吗?(除了同步它并等待initialize()直到从其他线程调用 setter 方法)。 github 上的完整代码用于上下文。


阿波罗的战车
浏览 292回答 2
2回答

饮歌长啸

如果要通过反射创建实例,则需要使用1后跟.Class.getConstructor(Class...)Constructor.newInstance(Object...)FXMLLoader loader = new FXMLLoader(/* some location */);loader.setControllerFactory(param -> {     Object controller;     try {         controller = param.getConstructor().newInstance();     } catch (ReflectiveOperationException ex) {        throw new RuntimeException(ex);     }     if (controller instanceof Swappable) {         ((Swappable) controller).setSwapper(swapper);     }     return controller;}此代码要求您的控制器类具有公共的无参数构造函数。如果您想通过构造函数注入您的依赖项,您可以执行以下操作:FXMLLoader loader = new FXMLLoader(/* some location */);loader.setControllerFactory(param -> {     Object controller;     try {        if (Swappable.class.isAssignableFrom(param)) {             controller = param.getConstructor(Swapper.class).newInstance(swapper);         } else {             controller = param.getConstructor().newInstance();         }     } catch (ReflectiveOperationException ex) {        throw new RuntimeException(ex);     }     return controller;}此代码假定 的所有子类Swappable都有一个公共的单参数构造函数,该构造函数采用Swapper.如果您想获得非公共构造函数,则需要使用Constructor.getDeclaredConstructor(Class...). 然后你需要调用setAccessible(true)在Constructor调用它之前。如果使用 Jigsaw 模块(Java 9+)并且此控制器工厂代码与控制器类不在同一个模块中,则需要记住一些事情。假设控制器工厂代码在 module 中foo,控制器类在 module 中bar:如果使用的是公共控制器的公共构造则bar必须exports控制器类的包至少foo如果使用非公共控制器和/或构造函数,则必须发生同样的事情,但使用opens而不是exports否则会抛出异常。1.如果使用无参数(不一定是公共)构造函数,您可以绕过getConstructor并Class.newInstance()直接调用。但是,请注意,此方法存在问题,并且自 Java 9 以来已被弃用。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java