简体   繁体   中英

Passing class name as a parameter

I have following function

public void loadWindowAndSendDataTest(String path, String appName, ConnectionData connectionData) {
    try {
        Stage subWindow = new Stage();
        subWindow.initModality(Modality.APPLICATION_MODAL);
        FXMLLoader loader = new FXMLLoader();
        Parent parent = loader.load(getClass().getResource(path).openStream());
        ExitController exitController = (ExitController) loader.getController();
        exitController.getConnectionData(connectionData);

        Scene scene = new Scene(parent);

        subWindow.setScene(scene);
        subWindow.setTitle(appName);
        subWindow.show();
    } catch(IOException e) {
        e.printStackTrace();
    }

And what I'd like to achive is to have more general function where I can pass class name (in this case ExitController), so it would like something like this:

public void loadWindowAndSendDataTest(String path, String appName, ConnectionData connectionData, String className) {
    try {
        Stage subWindow = new Stage();
        subWindow.initModality(Modality.APPLICATION_MODAL);
        FXMLLoader loader = new FXMLLoader();
        Parent parent = loader.load(getClass().getResource(path).openStream());
        /* do sth with className to obtain UsedClassController class */
        UsedClassController usedClassController = (UsedClassController) loader.getController();
        usedClassControler.getConnectionData(connectionData);

        Scene scene = new Scene(parent);

        subWindow.setScene(scene);
        subWindow.setTitle(appName);
        subWindow.show();
    } catch(IOException e) {
        e.printStackTrace();
    }

The assumption is that the class I'm passing to this function have getConnectionData() fuction implemented. Is there a way to do this?

You should create an interface with method getConnectionData() , implement this interface in your UsedClassController class.

To get name of the class try to use getSimpleName() from class object. Example for BigDecimal:

 BigDecimal.class.getSimpleName();

will return BigDecimal . If you want to get the name with package, you can use getCanonicalName()

If you're assuming the controller class has the getConnectionData(ConnectionData) method implemented, you could just use reflection to invoke that method:

public void loadWindowAndSendDataTest(String path, String appName, ConnectionData connectionData) {
    try {
        Stage subWindow = new Stage();
        subWindow.initModality(Modality.APPLICATION_MODAL);
        FXMLLoader loader = new FXMLLoader();
        Parent parent = loader.load(getClass().getResource(path).openStream());
        Object controller = loader.getController();
        Method getConnectionDataMethod = 
            controller.getClass().getMethod("getConnectionData", ConnectionData.class);
        getConnectionDataMethod.invoke(controller, connectionData);

        Scene scene = new Scene(parent);

        subWindow.setScene(scene);
        subWindow.setTitle(appName);
        subWindow.show();
    } catch(Exception e) {
        e.printStackTrace();
    }
}

This isn't a particularly robust or elegant approach. Perhaps better is to define an interface with the getConnectionData method:

public interface ConnectionDataProvider {

    public void getConnectionData(ConnectionData data) ;

}

and to have your controllers implement that method:

public class ExitController implements ConnectionDataProvider {

    public void getConnectionData(ConnectionData data) {
        // ...
    }

    // existing code ...
}

Then you can just assume the controller is from a class implementing that method:

public void loadWindowAndSendDataTest(String path, String appName, ConnectionData connectionData) {
    try {
        Stage subWindow = new Stage();
        subWindow.initModality(Modality.APPLICATION_MODAL);
        FXMLLoader loader = new FXMLLoader();
        Parent parent = loader.load(getClass().getResource(path).openStream());
        ConnectionDataProvider controller = loader.getController();
        controller.getConnectionData(connectionData);

        Scene scene = new Scene(parent);

        subWindow.setScene(scene);
        subWindow.setTitle(appName);
        subWindow.show();
    } catch(Exception e) {
        e.printStackTrace();
    }
}

Note that neither of these approaches requires you to pass in the type (class) of the controller. If you really needed that for some reason, you could do the following (using the interface approach):

public <T extends ConnectionDataProvider> void loadWindowAndSendDataTest(
        String path, String appName, 
        ConnectionData connectionData, Class<T> controllerType) {

    try {
        Stage subWindow = new Stage();
        subWindow.initModality(Modality.APPLICATION_MODAL);
        FXMLLoader loader = new FXMLLoader();
        Parent parent = loader.load(getClass().getResource(path).openStream());
        T controller = loader.getController();

        // if you wanted to cast explicitly here, you could do:
        // T controller = controllerType.cast(loader.getController());

        controller.getConnectionData(connectionData);

        // do something with controllerType if you need....

        Scene scene = new Scene(parent);

        subWindow.setScene(scene);
        subWindow.setTitle(appName);
        subWindow.show();
    } catch(Exception e) {
        e.printStackTrace();
    }
}

and then you would invoke this with

loadWindowAndSendDataTest("/path/to/fxml", "Application Name", 
    connectionData, ExitController.class);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM