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);
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With