Pau*_*wog 0 java eclipse swing jar classloader
我的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)
Run Code Online (Sandbox Code Playgroud)
编辑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**
Run Code Online (Sandbox Code Playgroud)
插件使用它的构造函数加载,并创建一个面板,添加到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
Run Code Online (Sandbox Code Playgroud)
我的类将成为.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));
}
}
Run Code Online (Sandbox Code Playgroud)
我用以下命令编译了这个类:
C:\Mine\JAVA\J2SE\src\testingjar>javac -d classes src\test\CustomPanel.java
Run Code Online (Sandbox Code Playgroud)
现在为JAR文件创建清单文件,其内容如下:
Main-Class: test.CustomPanel
Run Code Online (Sandbox Code Playgroud)
请记住冒号(:)和包名称之间的空格即测试,在CustomPanel之后,按Enter并保存文件.
现在创建一个名为JAR的文件test.jar,我写了这些命令:
C:\Mine\JAVA\J2SE\src\testingjar>cd classes
C:\Mine\JAVA\J2SE\src\testingjar\classes>jar -cfm ..\test.jar ..\manifest.txt test
Run Code Online (Sandbox Code Playgroud)
现在使用这个.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();
}
});
}
}
Run Code Online (Sandbox Code Playgroud)
我通过编写这些命令来编译它:
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
Run Code Online (Sandbox Code Playgroud)
现在运行我写了这些命令:
C:\Mine\JAVA\J2SE\src\testingjar>cd classes
C:\Mine\JAVA\J2SE\src\testingjar\classes>java actualtest.ActualImplementation
Run Code Online (Sandbox Code Playgroud)
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);
}
}
Run Code Online (Sandbox Code Playgroud)
manifest.txt文件的内容将更改如下:
Main-Class: test.CustomFrame
Run Code Online (Sandbox Code Playgroud)
而将从.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();
}
});
}
}
Run Code Online (Sandbox Code Playgroud)
编译顺序与以前非常相似,如下所示:
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
Run Code Online (Sandbox Code Playgroud)
我得到的输出仍然相同.
最新编辑:
我刚刚发现,有时这个东西可以工作,而不是后者,当使用JAR文件时,你必须指定包含点运算符的类路径 .,就像
C:\Mine\JAVA\J2SE\src\testingjar>java -classpath test.jar;.; actualtest.CustomPanel
Run Code Online (Sandbox Code Playgroud)
这是当我把文件夹actualtest package里面的内容testingjar,然后上面的命令适用于这种情况.