簡體   English   中英

Java:為什么打包到jar文件中的代碼阻止外部類訪問?

[英]Java: why code packaged into a jar file prevent external classes from accessing?

我的Java應用程序有一個插件系統。 我使用URL類加載器調用外部類。 無論是當我的應用程序作為類文件運行時,還是當我的應用程序為JAR形式時,該部分都可以正常工作。 我遇到的問題是,插件文件可以很好地運行自己的獨立代碼,但是它們創建了一個JPanel。 當我嘗試將該JPanel添加到主應用程序類中的JPanel時,出現一個空指針異常,該異常引用主類。 (com.cpcookieman.app.Main)但是,如果我為應用程序運行類文件(僅在打包時),則不會發生這種情況。 我該如何解決?

為什么將我的代碼打包到jar文件中,會阻止外部類訪問jar中的類?

編輯:根據要求,堆棧跟蹤。

java.lang.NullPointerException
    at TestPlugin2.Main.<init>(Main.java:23)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
    at java.lang.reflect.Constructor.newInstance(Unknown Source)
    at java.lang.Class.newInstance0(Unknown Source)
    at java.lang.Class.newInstance(Unknown Source)
    at com.cpcookieman.ph.PluginLoader$2.run(PluginLoader.java:74)
    at java.lang.Thread.run(Unknown Source)

編輯2:類加載代碼

    String pluginsPath;
    if (Main.os.equals("Windows"))
    {
        pluginsPath = "C:\\plugins\\";
    }
    else
    {
        pluginsPath = "~/plugins/";
    }
    File file = new File(pluginsPath);
    if (!file.exists())
    {
        System.out.println("DEBUG: Plugin path could not be found!");
    }
    try
    {
        URL url = file.toURI().toURL();
        final URL[] urls = new URL[]{url};
        new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                try
                {
                    ClassLoader cl = new URLClassLoader(urls);
                    Class plugin = cl.loadClass(text + ".Main");
                    plugin.newInstance();
                    close();
                }
                **snip catch statements**
            }
        }).start();
    }
    **snip catch statements**

插件使用其構造函數加載並創建一個面板,該面板將添加到JAR文件中的一個類內的框架。 如果有人對此感到困惑,那么JAR是主要應用程序。

我確實不知道您項目的結構,盡管我編寫了一個小示例代碼供您查看。

考慮我的項目位於C:\\Mine\\JAVA\\J2SE\\src\\testingjar>

在此我的目錄結構如下:

                         testingjar
                             |
              ----------------------------------
             |          |           |          |
          classes      src    manifest.text  test.jar(this .jar we be creating shortly)
             |          |
             |       (Almost same as classes folder, just .java files)
      ---------------
      |             |
  actualtest       test
      |             |
   *.class       *.class

我的班級將成為.jar文件的一部分,如下所示:

package test;

import java.awt.*;
import javax.swing.*;

public class CustomPanel extends JPanel
{
    public CustomPanel()
    {
        setOpaque(true);
        setBackground(Color.DARK_GRAY);

        JLabel label = new JLabel(
            "I am a JLabel from Java Swing", JLabel.CENTER);
        label.setOpaque(false); 
        label.setForeground(Color.WHITE);
        add(label); 
    }

    @Override
    public Dimension getPreferredSize()
    {
        return (new Dimension(500, 300));
    }
}

我使用以下命令編譯了此類:

C:\Mine\JAVA\J2SE\src\testingjar>javac -d classes src\test\CustomPanel.java

現在為JAR文件創建清單文件,其內容如下:

Main-Class: test.CustomPanel

請記住切記冒號(:)和程序包名稱(即test)之間的空格,在CustomPanel之后,按Enter鍵並保存文件。

現在創建一個名為test.jar的JAR文件,我編寫了以下命令:

C:\Mine\JAVA\J2SE\src\testingjar>cd classes

C:\Mine\JAVA\J2SE\src\testingjar\classes>jar -cfm ..\test.jar ..\manifest.txt test

現在,將使用此.jar文件的類將如下所示:

package actualtest;

import test.CustomPanel;

import java.awt.*;
import javax.swing.*;

public class ActualImplementation
{
    private void createAndDisplayGUI()
    {
        JFrame frame = new JFrame("Testing Jar Implementation");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        CustomPanel panel = new CustomPanel();
        frame.setContentPane(panel);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String... args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                new ActualImplementation().createAndDisplayGUI();
            }
        });
    }
}

我通過編寫以下命令對此進行了編譯:

C:\Mine\JAVA\J2SE\src\testingjar\classes>cd..

C:\Mine\JAVA\J2SE\src\testingjar>javac -classpath test.jar -d classes src\actualtest\ActualImplement
ation.java

現在運行,我寫了以下命令:

C:\Mine\JAVA\J2SE\src\testingjar>cd classes

C:\Mine\JAVA\J2SE\src\testingjar\classes>java actualtest.ActualImplementation

OUTPUT

JAR實施

請按步驟操作,可能是您缺少了某些東西,因為它在我這方面工作正常。

最新編輯:按要求,我做了另一種方法,現在JFrame位於.jar文件中,而JPanel正在使用它。

將成為.jar文件一部分的類如下:

package test;

import java.awt.*;
import javax.swing.*;

public class CustomFrame extends JFrame
{
    public CustomFrame(String title)
    {
        super(title);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }
}

manifest.txt文件的內容將更改如下:

Main-Class: test.CustomFrame

並且將使用來自.jar文件的CustomFrame Class的類如下:

package actualtest;

import test.CustomFrame;

import java.awt.*;
import javax.swing.*;


// http://stackoverflow.com/a/11150286/1057230
public class CustomPanel extends JPanel
{
    private CustomFrame frame;

    public CustomPanel()
    {
        setOpaque(true);
        setBackground(Color.DARK_GRAY);

        JLabel label = new JLabel(
            "I am a JLabel from Java Swing", JLabel.CENTER);
        label.setOpaque(false); 
        label.setForeground(Color.WHITE);
        add(label);                 
    }

    private void createAndDisplayGUI()
    {
        frame = new CustomFrame("Testing Jar Implementation");
        frame.setContentPane(this);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    @Override
    public Dimension getPreferredSize()
    {
        return (new Dimension(500, 300));
    }

    public static void main(String... args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                new CustomPanel().createAndDisplayGUI();
            }
        });
    }
}

編譯順序與以前非常相似,如下所示:

C:\Mine\JAVA\J2SE\src\testingjar>javac -d classes src\test\CustomFrame.java

C:\Mine\JAVA\J2SE\src\testingjar>cd classes

C:\Mine\JAVA\J2SE\src\testingjar\classes>jar -cfm ..\test.jar ..\manifest.txt test

C:\Mine\JAVA\J2SE\src\testingjar\classes>cd..

C:\Mine\JAVA\J2SE\src\testingjar>javac -classpath test.jar -d classes src\actualtest\CustomPanel.jav
a

C:\Mine\JAVA\J2SE\src\testingjar>cd classes

C:\Mine\JAVA\J2SE\src\testingjar\classes>java actualtest.CustomPanel

還是一樣的輸出,我得到了。

最新編輯:

我剛剛發現,有時候這件事可行,而不是后來的事,當使用JAR文件時,您還必須指定類路徑,包括點運算符. , 喜歡

C:\Mine\JAVA\J2SE\src\testingjar>java -classpath test.jar;.; actualtest.CustomPanel

這是當我將actualtest package帶入testingjar文件夾時,以上命令在這種情況下有效。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM