Consider this - I have a simple one-class application called "TestApplication" (source code below):
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class TestApplication extends Application {
public Parent createContent() {
/*layout*/
BorderPane layout = new BorderPane();
/*layout -> center*/
Button button = new Button("Run JAR");
button.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent ae) {
// Call TestJar.class from TestJar.jar
}
});
/*add item to the layout*/
layout.setCenter(button);
return layout;
}
@Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent()));
stage.setWidth(200);
stage.setHeight(200);
stage.show();
}
public static void main(String args[]) {
launch(args);
}
}
Now, in its button.setOnAction()
method I want to call a "TestJar.class" (extends javafx.stage.Stage), which is the only class of non-runnable "TestJar.jar" archive. But problem is, I want to be able to call "TestJar.class" from the level of "TestApplication" without the prior possibility of adding imports to the code. For example I have an application, for which I provide jar location and information about the name of the class in this jar, which should be call out. Code of the "TestJar.java" class below:
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class TestJar extends Stage {
public TestJar() {
super();
BorderPane layout = new BorderPane();
Label label = new Label("This is test");
layout.setCenter(label);
Scene scene = new Scene(layout, 200, 200);
this.setScene(scene);
this.show();
}
}
And additionaly structure of the JAR file:
<archive = TestJar.jar>
<folder = META-INF>
<file = MANIFEST.MF>
Manifest-Version: 1.0
</file>
</folder>
<file = .classpath>
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="output" path="bin"/>
</classpath>
</file>
<file = .project>
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>TestJar</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
</file>
<file = TestJar.class></file>
</archive>
Is there any way I can call that "TestJar" class programmably from my "TestApplication" class?
UPDATE 2014/07/26, 11:37AM
I've used the example written by @Allain Lalonde in How should I load Jars dynamically at runtime? called ClassPathHack
Next, I've merged his solution with suggestion made in this topic by @Doswell, which looks like this:
button.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent ae) {
try {
ClassPathHack.addFile("C:/Users/John Smith/Desktop/TestJar.jar");
Class<?> clazz = Class.forName("TestJar");
Stage testJar = (Stage) clazz.newInstance();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
})
Everything works perfectly. Thank you!