为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

阿波罗的战车 2021-07-08 14:17:42
我想initialize在创建时自动调用控制器的方法之前在控制器中设置一些非 UI 字段。据我了解,这样做的方式是定制的提供ControllerFactory,因为initialize()被调用后 ControllerFactory返回创建的对象。我想根据这个答案使用以下代码:FXMLLoader loader = new FXMLLoader(mainFXML); // some .fxml file to loadloader.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 上的完整代码用于上下文。
查看完整描述

2 回答

?
饮歌长啸

TA贡献1951条经验 获得超3个赞

如果要通过反射创建实例,则需要使用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.如果使用无参数(不一定是公共)构造函数,您可以绕过getConstructorClass.newInstance()直接调用。但是,请注意,此方法存在问题,并且自 Java 9 以来已被弃用。


查看完整回答
反对 回复 2021-07-14
  • 2 回答
  • 0 关注
  • 291 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信