通过控制器工厂传递构造函数参数的问题

Issue with passing constructor parameter via controller factory

我在向控制器传递参数时遇到了问题。主程序使用控制器工厂将阶段对象传递给我的控制器。控制器工厂打印阶段对象的地址,但控制器获取 Null 作为阶段对象。为什么?

虽然我已经将我的应用程序简化为一个简单的对话,但我找不到我的错。我希望你能帮忙。谢谢!

主程序:

public class Main extends Application {
private final Logger logger = Logger.getLogger(this.getClass().getName());
private final String FXML_SIMPLE_DIALOG = "testDialog.fxml";
private MyHandler myHandler = new MyHandler();

@Override
public void init() {
    try{
        // Thread.currentThread is the FX-Launcher thread:
        Thread.currentThread().setUncaughtExceptionHandler(myHandler);
        try {
            logger.addHandler(new FileHandler("java.myLOG"));
        }
        catch (IOException e) {
            throw new IllegalStateException("IOException when adding File Handler");
        }
    }
    catch (Exception ex) {
        myHandler.uncaughtException(Thread.currentThread(), ex);
        throw(ex);
    }
}
@Override
public void start(Stage primaryStage) {
    try{
        logger.info("Test Application started");
        Thread.currentThread().setUncaughtExceptionHandler(myHandler);
        try{
            URL location = new URL(this.getClass().getResource("resources/fxml/" + FXML_SIMPLE_DIALOG).toString());
            FXMLLoader loader = new FXMLLoader(location);
            loader.setControllerFactory(new SimpleControllerFactory(primaryStage));
            Pane root = loader.load();
            Scene scene = new Scene(root);
            primaryStage.setScene(scene);
            primaryStage.setTitle("*** TEST App ***");
            primaryStage.show();
        }
        catch(IOException ex) {
            ex.printStackTrace();
            throw new IllegalStateException("check program source code!");
        }
    }
    catch(Exception ex) {
        myHandler.uncaughtException(Thread.currentThread(), ex);
        throw(ex);
    }
}

public static void main(String[] args) {
    launch(args);
}

class MyHandler implements Thread.UncaughtExceptionHandler{
    @Override
    public void uncaughtException(Thread thread, Throwable throwable) {
        logger.log(Level.SEVERE, "** STOPP ** due to uncaught exception", throwable);
        Platform.exit();
    }
}

}

控制器出厂代码:

public class SimpleControllerFactory implements Callback<Class<?>,Object> {
private static final Logger logger = Logger.getLogger(SimpleControllerFactory.class.getName());
private final Stage primaryStage;

public SimpleControllerFactory(Stage stage) {
    this.primaryStage = stage;
    System.out.println("controller factory: value of stage: " + this.primaryStage);
}
public SimpleControllerFactory() { this(null); }

@Override
public Object call(Class<?> type) {
    try {
        for (var c : type.getConstructors()) {

            switch(c.getParameterCount()) {
                case 0 -> {}
                case 1 -> {
                    if ( c.getParameterTypes()[0] == Stage.class) {
                        return c.newInstance(primaryStage) ;
                    }
                    else;
                }
                default -> {}
            }
        }
        return type.getDeclaredConstructor().newInstance();
    }
    catch (InvocationTargetException | InstantiationException | IllegalAccessException | NoSuchMethodException ex) {
        logger.log(Level.SEVERE,ex.toString(),ex);
        throw new RuntimeException(ex);
    }
}

}

这是 FXML 文件和简单的控制器:

<VBox prefHeight="150.0" prefWidth="250.0" spacing="5.0" style="-fx-padding: 5 5 5 5;-fx-font-size: 11px"
  xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1"
  fx:controller="TestSimpleDialog.DialogController">
<children>
    <ButtonBar buttonOrder="UL_HE+FBIX_NCYOA_R" prefHeight="40.0">
        <buttons>
            <Button alignment="CENTER" mnemonicParsing="false" onAction="#time" text="time ?">
            </Button>
        </buttons>
    </ButtonBar>
    <StackPane VBox.vgrow="ALWAYS">
        <children>
            <Label fx:id="textTime" alignment="CENTER" text="" />
        </children>
    </StackPane>

</children>

简单控制器:

public class DialogController implements Initializable {

private static final Logger logger = Logger.getLogger(DialogController.class.getName());
private final Stage recentStage;

DialogController(Stage stage) {
    this.recentStage = stage;
}
DialogController() { this(null); }

@FXML private Label textTime;

@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
    System.out.println("Controller started, value of recentStage: " + this.recentStage);
}

@FXML
private void time(ActionEvent event) {
    textTime.setText(LocalDateTime.now().format(DateTimeFormatter.ofPattern("dd.MM.yyyy kk:mm:ss")));
}

}

Class.getConstructors()方法

Returns an array containing Constructor objects reflecting all the public constructors of the class represented by this Class object.

(我的重点)。

由于您的构造函数未声明 [​​=36=],因此工厂 call(...) 方法中的 for 循环迭代零次,并且默认调用 no-arg构造函数。

只需将构造函数声明为 public 即可:

public class DialogController implements Initializable {

    private final Stage recentStage;

    public DialogController(Stage stage) {
        this.recentStage = stage;
    }
    public DialogController() { this(null); }

    // ...
}

如果您真的想要保留构造函数non-public,您可以使用getDeclaredConstructor(...)方法来检索特定的构造函数,而不必成为 public:

@Override
public Object call(Class<?> type) {
    try {
        System.out.println("Number of constructors found: "+type.getConstructors().length);
        try {
            Constructor<?> c = type.getDeclaredConstructor(Stage.class);
            return c.newInstance(primaryStage);
        } catch (NoSuchMethodException e) {

            return type.getDeclaredConstructor().newInstance();
        }
    }
    catch (InvocationTargetException | InstantiationException | IllegalAccessException | NoSuchMethodException ex) {
        logger.log(Level.SEVERE,ex.toString(),ex);
        throw new RuntimeException(ex);
    }
}