1

I'm making a Maven project with Jython. In Eclipse it runs fine, but when I run the exported jar it trows an exception.

This are my directories inside src/main/resources:

src/main/resources:
    mylib
        file_one.py
        file_two.py
    pylib
        sys.py
        sys$py.class
        os.py
        os$py.class
        ...

I've been trying to load my folder pylib containing class files in src/main/resources with this snippet of code:

public class MyClass {

    // ...

    public static void init() {
        // ...
        ClassLoader classLoader = Prompt.class.getClassLoader();
        addToPath(path, classLoader.getResource("mylib").getPath());
        System.out.println("Found mylib");
        addToPath(path, classLoader.getResource("pylib").getPath());
        System.out.println("Found pylib");
        // ...
    }

    // ...

}

While exporting to jar I got this error:

JAR export finished with warnings. See details for additional information.
  Problem writing project/src/main/resources/.DS_Store to JAR: duplicate entry: .DS_Store
  duplicate entry: .DS_Store

I tested it multiple times, but the jar only included the folder mylib that didn't contain class files. If I included pylib I got this error:

java.lang.NullPointerException
    at *project*.Prompt.init(Prompt.java:53)
    at *project*.Prompt.start(Prompt.java:76)
    at *project*.Main.main(Main.java:6)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:58)
Exception in thread "main" java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:58)

Note: I replaced my group id with *package* to hide the identity of my project.

Does anyone know how to load the class files?

Edit:

  • Corrected code by adding semicolons.
  • Added println expression to make clear where the executed jar failed.
  • Added path information.
  • Changed class and project name.
  • Added export error.
  • Extended runtime error
Dylan
  • 11
  • 3
  • 1
    Are you trying to load python files in java? – Dan Grahn May 31 '17 at 18:51
  • Yes I am, using Jython – Dylan Jun 01 '17 at 10:50
  • check if `pylib` is in the JAR file (jar -tvf project.jar) – user85421 Jun 01 '17 at 14:39
  • Yes there is: `0 Thu Jun 01 16:57:38 CEST 2017 pylib/` – Dylan Jun 01 '17 at 15:04
  • @CarlosHeuberger If you look at the dollar sign in `sys$py.class`, maybe --> [this](https://stackoverflow.com/questions/7484210/what-is-the-meaning-of-in-a-variable-name) has to do something with my problem. If somebody knows why and how to fix it, *please answer.* – Dylan Jun 01 '17 at 15:19
  • in the JAR file? it's just strange that it apparently is not finding the `pylib` as resource... at least I think it is that line that is throwing the exception. maybe it helps if you print out the result of `classLoader.getResource("pylib")` and `classLoader.getResource("pylib").getPath()`. Also unconventional to have .class files in the `src/` tree... could be the problem if Prompt.class is under a different folder/tree. – user85421 Jun 01 '17 at 15:28
  • @CarlosHeuberger I extended the exception above. I tried to put the `pylib` folder at the root of the project but that didn't work either. I also tried to replace the `$`s by `_`s, but that also didn't work. – Dylan Jun 01 '17 at 16:01
  • why root? Is your Prompt.class behind loaded from there? Anyway I will stop guessing and wait for ""you print out the result of classLoader.getResource("pylib") and classLoader.getResource("pylib").getPath()"" – user85421 Jun 01 '17 at 16:10
  • @CarlosHeuberger I forgot to answer that. Direct answer: It throws an `java.lang.NullPointerException` – Dylan Jun 01 '17 at 16:18
  • the first one - `classLoader.getResource("pylib")`?? hmm, would mean that the Prompt.class has no ClassLoader [:-0 (instead of a direct answer, a detailed one would be better) – user85421 Jun 01 '17 at 16:19
  • @CarlosHeuberger Though `classLoader.getResource("mylib")` the directory without classes, didn't throw an Exception. – Dylan Jun 01 '17 at 16:31
  • I suspect that getting a directory as resource from a JAR file will not work (always). Try with `classLoader.getResource("pylib/sys$py.class")...` or with any other file in that directory – user85421 Jun 01 '17 at 17:12
  • @CarlosHeuberger It still works in eclipse, but doesn't in the executed jar. – Dylan Jun 02 '17 at 07:02
  • see my answer, comments are to hard to format... – user85421 Jun 02 '17 at 08:09

1 Answers1

0

The problem must be how the JAR file was created or what is in it.

I just did a mostly minimal complete sample. Works in Eclipse, Windows command prompt, Git Bash and SUSE Linux!

Directory structure:

./bin
./bin/classes
./bin/classes/project
./bin/classes/project/Prompt.class
./bin/classes/pylib
./bin/classes/pylib/file.txt
./py.jar
./py.jardesc
./src
./src/java
./src/java/project
./src/java/project/Prompt.java
./src/java/pylib
./src/java/pylib/file.txt

Prompt.java:

package project;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

public class Prompt {

    public static void main(String[] args) {
        ClassLoader cl = Prompt.class.getClassLoader();
        URL url;
        url = cl.getResource("pylib");
        System.out.println(url);

        url = cl.getResource("pylib/file.txt");
        System.out.println(url);
        try (InputStream in = url.openStream()) {
            int ch;
            while ((ch = in.read()) != -1) {
                System.out.print((char) ch);
            }
            System.out.println();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}

file.txt (for testing):

Just a test

JAR created by Eclipses JAR Export Wizard with following settings:

  1. selecting resources to export: "project" and "pylib" directories
  2. activating "Export generated class files and resources
  3. selecting option "Add directory entries"
  4. choosing "Generate the manifest file"
  5. entering "project.Prompt" as Main class

The content of the JAR is (first line is prompt and the command to generate that listing):

$ jar -tvf py.jar
    53 Fri Jun 02 07:42:02 UTC 2017 META-INF/MANIFEST.MF
     0 Fri Jun 02 07:34:10 UTC 2017 pylib/
    11 Fri Jun 02 07:34:20 UTC 2017 pylib/file.txt
     0 Fri Jun 02 07:36:34 UTC 2017 project/
  1480 Fri Jun 02 07:41:54 UTC 2017 project/Prompt.class

Executed by:

  1. Eclipse: Run as > Java Application
  2. DOS/Command prompt: java -jar py.jar
  3. DOS/Command prompt: java -cp py.jar project.Prompt
  4. Git Bash: java -jar py.jar
  5. Git Bash: java -cp py.jar project.Prompt
  6. SUSE Linux, different computer, empty folder: java -jar py.jar
  7. SUSE Linux, different computer, empty folder: java -cp py.jar project.Prompt

It generates almost the same output for all the above cases, just the path is different:

Eclipse:

file:/C:/DEVELOP/ECLIPSE/test/bin/classes/pylib
file:/C:/DEVELOP/ECLIPSE/test/bin/classes/pylib/file.txt
Just a test

DOS prompt, Git Bash:

jar:file:/C:/DEVELOP/ECLIPSE/test/py.jar!/pylib
jar:file:/C:/DEVELOP/ECLIPSE/test/py.jar!/pylib/file.txt
Just a test

SUSE Linux:

jar:file:/home/user/pytest/py.jar!/pylib
jar:file:/home/user/pytest/py.jar!/pylib/file.txt
Just a test

Compiled and executed with Java 8 on Windows; executed with Java 9 on SUSE Linux.

user85421
  • 28,957
  • 10
  • 64
  • 87
  • 'file.txt' is used just for testing access to a file (and I know I could/should use a buffer to read it...) – user85421 Jun 02 '17 at 08:28
  • Your settings almost worked by making one little change: **selecting option "Export all output folders for checked projects"**! The only thing that's now happening is that my `jython-2.7.0.jar` can't find the resources from the path. I'll be trying to change the `jython-2.7.0.jar/META-INF/MANIFEST.MF` to detect the `project/resources` folder. – Dylan Jun 02 '17 at 13:59