Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reflected Method calling constructor multiple times

I'm working on launching a JavaFX GUI app using a custom classloader and reflection, however I seem to be inadvertently invoking the application constructor multiple times, which throws an exception (using a sort of singleton pattern to guarantee nobody tries to re-initialize the main app class).

The MyApp constructor's IllegalStateException is thrown when I call startupMethod.invoke(instance); from my Launcher class.

public class MyApp extends Application {

    private static MyApp instance = null;

    private static boolean started = false;

    public MyApp() {
        if (instance != null) {
            throw new IllegalStateException("MyApp already initialized");
        }
        instance = this;
    }

    public static MyApp getInstance() {
        return instance;
    }

    public void startup() {
        synchronized (LOCK) {
            if (started == true) {
                throw new IllegalStateException("MyApp is already running");
            }
        }
       // do things to start the GUI, etc...
       //  ... ... ...
       started = true;
       launch(); // static method part of the JavaFX platform
    }

    @Override
    public void start(final Stage stage) {
        // do stuff to display GUI
    }

}

.

public class Launcher {

    public static void main(String[] args) {
        new Launcher().start();
    }

    private void start() {
        // create custom classloader ...
        // ... ... ...
        Class<?> myAppClass = myLoader.loadClass("com.something.MyApp");
        // calls the MyApp constructor and sets the "instance" static var to "this"
        Object instance = myAppClass.newInstance();

        Method startupMethod = myAppClass.getMethod("startup");
        // this seems to call the MyApp constructor again!, exception thrown...
        startupMethod.invoke(instance);
    }

}

If I comment out the exception in the MyApp constructor, the app starts up just fine, but it means I've still invoked the constructor twice and I'm unsure why. I need to be able to guard against people invoking this constructor more than once.

EDIT: With some research, it's appearing that the call to the static method Application.launch() is attempting to build a new instance of MyApp on the JavaFX application thread...

UPDATE:

Fixed by adding a static method into MyApp which just invokes the Application.launch() method. From the Launcher class I just load the MyApp class and then call the static method like:

public class MyApp extends Application {
    public MyApp() {
        if (instance != null) {
            throw new IllegalStateException("Already initialized");
        }
        instance = this;
    }
    // other stuff
    public static void startup() {
        launch();
    }
}

.

public class Launcher {
    // other stuff
    Class<?> myAppClass = myLoader.loadClass("com.something.MyApp");
    Method startupMethod = myAppClass.getMethod("startup");
    startupMethod.invoke(null, null);
}
like image 389
SnakeDoc Avatar asked Aug 06 '26 13:08

SnakeDoc


1 Answers

Application.launch() creates an instance of the class on which it was called (necessarily a subclass of Application). That's where the second instance is coming from.

like image 199
James_D Avatar answered Aug 09 '26 03:08

James_D



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!