且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何在java程序中从非可运行的JAR中调用类?

更新时间:2023-09-29 22:37:10

如果您要从jar运行的类扩展/实现您在代码中已知的内容可以使用反射加载类,但可以使用它,就像你知道的那样,即javafx.stage.Stage vs TestJar。



如果JAR已经在类路径中你可以做;

 类<?> clazz = Class.forName(TestJar); 
阶段testJar =(阶段)clazz.newInstance();

如果类路径上没有JAR,但确实有jar的路径,你可以按照这个我该如何加载一个罐子
然后加载上面的类


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!

If the class you want to run from the jar extends/implements something you know about in your code already you can use reflection to load the class but work with it as whatever it is you know it as ie javafx.stage.Stage vs TestJar.

If the JAR is already on the classpath you can just do;

Class<?> clazz = Class.forName("TestJar");
Stage testJar = (Stage)clazz.newInstance();

If you don't have the JAR on the classpath, but do have the path to the jar, you can follow this How should I load a jar And then load the class as above