Java:为什么代码打包成jar文件阻止外部类访问? [英] Java: why code packaged into a jar file prevent external classes from accessing?

查看:266
本文介绍了Java:为什么代码打包成jar文件阻止外部类访问?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个我的Java应用程序的插件系统。我用URL类加载器调用一个外部类。当我的应用程序作为类文件运行时,以及当我的应用程序处于JAR格式时,该部分运行良好。我遇到的问题是,插件文件可以运行自己的独立代码,但它们创建了一个JPanel。当我尝试将JPanel添加到主应用程序类中的JPanel时,我得到一个引用主类的空指针异常。 (com.cpcookieman.app.Main)但是,如果我运行应用程序的类文件,只有当它被打包时才会发生。我如何解决这个问题?



为什么我的代码打包成一个jar文件阻止外部类访问jar内的类?



编辑:根据请求,堆栈跟踪。

  java.lang.NullPointerException 
在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)
在java.lang.reflect.Constructor.newInstance(未知来源)
在java.lang.Class.newInstance0(未知来源)
在java.lang.Class.newInstance(未知来源)
在com.cpcookieman.ph.PluginLoader $ 2.run(PluginLoader.java:74)
在java.lang.Thread.run(未知来源)

编辑2:课程加载代码

  String pluginsPath; 
if(Main.os.equals(Windows))
{
pluginsPath =C:\\\plugins\\;
}
else
{
pluginsPath =〜/ plugins /;
}
文件文件=新建文件(pluginsPath);
if(!file.exists())
{
System.out.println(DEBUG:Plugin path does 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语句**
}
})。start();
}
** snip catch语句**

插件加载使用它是构造函数,并创建一个要添加到框架内的面板,该框架位于JAR文件中的一个类内。 JAR是主要的应用程序,如果有人对此感到困惑。

解决方案

我真的不知道你的项目的结构,虽然我已经提供了一个小例子代码,看看,看看。



考虑到我的项目位于 C:\ Mine \JAVA\J2SE\src\testingjar>



这里我的目录结构如下:

  testingjar 
|
----------------------------------
| | | |
类src manifest.text test.jar(这个.jar我们很快创建)
| |
| (几乎和classes文件夹一样,只有.java文件)
---------------
| |
actualtest test
| |
* .class * .class

我的类将成为.jar的一部分文件,如下所示:

 包测试; 

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

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

JLabel label = new JLabel(
我是Java Swing中的JLabel,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类src\test\CustomPanel.java 

现在为JAR文件创建清单文件,其内容如下:

 主类:test.CustomPanel 
<记住冒号(:)和包名称之间的空格,即test,并在CustomPanel之后,按下键输入并保存文件。



现在创建名为的JAR文件test.jar ,我写了这些命令:

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

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类

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

OUTPUT





做出匹配的步骤,可能你会缺少一些东西,因为它在我身边工作正常。



最新编辑:As as ked,我这样做了,而现在的 JFrame 在.jar文件中,而 JPanel 正在使用它。



将成为.jar文件一部分的类如下:

 包测试; 

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

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

清单的内容。 txt文件将更改如下:

 主类: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扩展JPanel
{
private CustomFrame frame;

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

JLabel label = new JLabel(
我是Java Swing中的JLabel,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类src\test\CustomFrame.java 

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

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;。 realtest.CustomPanel 

这是当我带来 actualtest testingjar 文件夹中,c> ,则上述命令用于此情况。


I have a plugin system for my Java app. I invoke an external class with the URL class loader. That part works well, both when my application is run as class files, and when my application is in JAR form. The problem that I am running into is, the plugin files can run their own independent code just fine, but they create a JPanel. When I try to add that JPanel to the JPanel that's in the main application class, I get a null pointer exception referencing the main class. (com.cpcookieman.app.Main) But that doesn't happen if I run the class files for the application, only when it's packaged. How can I solve that?

Why does my code being packaged into a jar file prevent external classes from accessing classes inside the jar?

EDIT: As requested, the stack trace.

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)

EDIT 2: The class loading code

    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**

The plugin loads up using it's constructor, and creates a panel to be added to the frame that's inside one of the classes inside the JAR file. The JAR is the main application, if anyone's confused about that.

解决方案

I really don't know the structure of your project, though I had made a small example code for you to look at, have a look.

Consider that my project is placed at C:\Mine\JAVA\J2SE\src\testingjar>

Inside this my directory structure is as below :

                         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

My Class that will become a part of a .jar file, is as given below :

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));
    }
}

I compiled this class with the following command :

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

Now Creating Manifest File for the JAR File, the contents of which are as follows :

Main-Class: test.CustomPanel

Do remember the space between colons (:) and the package name i.e. test, and after CustomPanel, Press Enter and save the file.

Now for creating a JAR File named test.jar, I wrote these commands :

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

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

Now the class that will use this .jar file will be like this :

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();
            }
        });
    }
}

I compiled this by writing these commands :

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

Now to run I wrote these commands :

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

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

OUTPUT

Do match the steps, might be you be missing something, since it's working fine on my side.

LATEST EDIT : As asked, I did that the other way around, now JFrame is inside the .jar file and JPanel is using it.

The class that will become the part of the .jar file is as follows :

package test;

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

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

Contents of the manifest.txt file, will change as follows :

Main-Class: test.CustomFrame

And the class which will use CustomFrame Class from the .jar file, is as follows :

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();
            }
        });
    }
}

The compilation sequence, is very much the same as before, which is as follows :

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

Still the same output, I am getting.

LATEST EDIT :

I just found out, that sometimes this thing works, instead of the later, when using JAR Files, you have to specify the classpath including the dot operator as well ., like

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

This is when I brought the actualtest package inside the testingjar Folder, then the above command worked for this situation.

这篇关于Java:为什么代码打包成jar文件阻止外部类访问?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆