Skip to content

How to change this JavaFX into using a ControllerFactory

I have looked into using ControllerFactory a lot, to allow this code to be instantiated from a database, and have cross-controller compatibility. But with my original setup different from others I found online, I found it extremely hard to follow along, and use what would fit into my program from theirs. Any advice on where to start?

Current Controller creation –

        // get Main Class package name to get correct files path
        String pathRef = mainRef.getClass().getPackage().getName();
        // set FXRouter current route reference
        currentRoute = route;
        // create correct file path.  "/" doesn't affect any OS
        String scenePath = "/" + pathRef + "/" + route.scenePath;

        // Creates controller for route
        Controller_Factory cf = new Controller_Factory();
        Object controller  = cf.CreateController(route.scenePath);

        FXMLLoader loader = new FXMLLoader(controller.getClass().getResource(scenePath));

        Parent root = loader.load();

        // set window title from route settings or default setting
        // set new route scene
        window.setScene(new Scene(root, route.sceneWidth, route.sceneHeight));
        // show the window;


Controller Example-

public class BuyController extends Controller {

    public Button CloseAppButton;
    @FXML public Button SwitchToProfileButton;
    @FXML public Button SwitchToSellButton;
    @FXML public Button SwitchToBuyButton;
    @FXML public Button SwitchToMainButton;

@FXML public TextField BuyText;

String AmountBought;

    public void initialize (URL location, ResourceBundle resources){




    public void OnBuyButton (ActionEvent event) {
AmountBought = BuyText.getText();
System.out.println("You have bought " + AmountBought + " of crypto");

    public void initilize(URL url, ResourceBundle rb) {



Current Controller_Factory-

public class Controller_Factory {

    private static final Controller_Factory instance = new Controller_Factory();

public static Controller_Factory getInstance() {
    return instance;

public Object CreateController (String routeScenePath) throws IllegalArgumentException, IOException {

    Object controller = null;

    switch (routeScenePath) {
        case  "Buy.fxml":
            controller = new BuyController();
        case "Error.fxml":
            controller = new ErrorController();
        case "Home.fxml":
            controller = new HomeController();
        case "Profile.fxml":
            controller = new ProfileController();
        case "Sell.fxml":
            controller = new SellController();

    return controller;


How would I pass this info with the said controller? (This is not real code I have, but an example of configuration JSON I want to pass with the controller.)

  "HomePage": {
    "ValidPages": [
    "InternalID": "HP"
  "BuyPage": {
    "ValidPages": [
    "InternalID": "BP",
    "Cryptos": [


The controller factory is simply a Callback<Class<?>, Object> whose call(Class<?> type) function takes the class defined in the fx:controller attribute in the FXML file and returns the object to be used as the controller. This is invoked by the FXMLLoader at the time the FXML is loaded.

I think your question is asking if you can use a controller factory to automatically populate controllers with data that’s stored in JSON, which will be read at runtime.

You can do something like this:

public class NavigationInfo {

    private final Map<String, PageNavigationInfo> pageInfoPerPage ;

    public NavigationInfo(Map<String, PageNavigationInfo pageInfoPerPage) {
        this.pageInfoPerPage = pageInfoPerPage;

    public PageNavigationInfo getInfoForPage(String page) {
        return pageInfoPerPage.get(page);
public class PageNavigationInfo {

    private final String internalID ;

    private final List<String> validPages ;

    private final List<String> cryptos ;

    // .... etc
public class NavigationControllerFactory implements Callback<Class<?>, Object> {

    private final NavigationInfo navigationInfo ;

    public NavigationControllerFactory() {
        // read and parse JSON and create NavigationInfo instance

    public Object call(Class<?> type) {
        try {
            for (Constructor<?> c : type.getConstructors()) {
                if (c.getParameterCount() == 1 && c.getParameterTypes()[0].equals(NavigationInfo.class)) {
                    return c.newInstance(navigationInfo);
            // no suitable constructor, just use default constructor as fallabck
            return type.getConstructor().newInstance();
        } catch (Exception e) {
            throw new RuntimeException(e);


Now just define the fx:controller attribute in each FXML in the usual way. E.g. for Buy.fxml do

<BorderPane ... fx:controller="com.yourcompany.yourproject.BuyController">

    <!-- ... -->


public class BuyController {

    private final PageNavigationInfo navInfo ;

    public BuyController(NavigationInfo navigationInfo) {
        this.navInfo = navigationInfo.getInfoForPage("BuyPage");

    private void initialize() {
        // do whatever you need with navInfo