[英]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
請按步驟操作,可能是您缺少了某些東西,因為它在我這方面工作正常。
最新編輯:按要求,我做了另一種方法,現在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.