0

I have some Java code on my machine that I run from the command line. I want to create a runnable .jar file from this code so that I can distribute my application more easily.

The code is in four folders, called fol_a, fol_b, fol_c, and fol_d. Each of these contains a /bin subfolder, containing the .class files, and two of them (fol_a and fol_b) also contain a /lib folder, containing some .jar files that the code needs.

fol_d contains the class to run, Demo, which is in a package called machineLearning. The full path to the class is

fol_d/bin/machineLearning/Demo 

I currently run the code from the command line as follows:

$ cd fol_d/bin
$ java -cp ".:../../fol_a/bin:../../fol_a/lib/*:../../fol_b/bin:../../fol_b/lib/*:../../fol_c/bin" machineLearning.Demo <param_1> <param_2> ... <param_5> 

where <param_1> to <param_5> are the arguments given to the Main method in Demo.

What I want is to create one single .jar file that contains all the code that is necessary to execute Demo successfully, i.e., the code in fol_a through fol_d. I then want to be able to run this .jar file from the command line, giving it the arguments that go to the Main method in Demo. Something like this:

$ java -jar MyApplication.jar <param_1> ... <param_5>

Is this possible? How would I do this? I've been trying to find an answer online, but the amount of information confuses me.

UPDATE

Right! So it seems that all I needed to do was this:

  • copy the contents of the bin directories to a new dir myapp
  • make a manifest.txt file that specifies the main class to run, as well as the classpath
  • jar myapp: $ jar cmf manifest.txt myapp.jar -C myapp/ .
  • execute the jar: $ java -jar myapp.jar <arg_1> <arg_2> ... <arg_n>
rdv
  • 682
  • 2
  • 8
  • 19

1 Answers1

2

Yes it is possible.

  1. Use "cp -R" to copy all 4 folders' bin directories into one directory ... preserving the subdirectory structures. (Read man cp if you don't understand how. Install the manual entries if they are not installed.)

  2. Use the jar command to create the JAR file from the consolidated directory.


UPDATE

When you create the JAR file, the paths within the JAR (i.e. in the JAR file index) must match the respective classes fully qualified names.

If you are creating an executable JAR, the Main Class attribute must specify the fully qualified class name.

If you misname the JAR file entries then either java won't find the classes, or it will refuse to load them because the pathname and classname don't match.

These requirements apply for all JARs, but from your comments it seems that you have overlooked this.

In your comment, you seem to have used the wrong classname in the Main Class attribute ... unless you declared the class in the fol_d.bin package!


UPDATE 2

Here is an example to illustrate my point about fully qualified classnames

package foo.bar;

public class Main {
   ...
}

The simple class name is Main. The fully qualified classname is foo.bar.Main. If you put the ".class" file for this class into a JAR, the pathname in the JAR file for the class must be:

/foo/bar/Main.class

The package name (foo.bar) maps to the directory path in the JAR file index; i.e. "/foo/bar".

If the pathname in the JAR file isn't that, then the classloader won't find it.

Graham
  • 7,431
  • 18
  • 59
  • 84
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • Before I try this - `man cp` informs me: "Historic versions of the cp utility had a -r option. This implementation supports that option; however, its use is strongly discouraged, as it does not correctly copy special files, symbolic links, or fifo's." Should I worry about this? – rdv Apr 02 '17 at 20:52
  • Use -R instead. – Stephen C Apr 02 '17 at 22:42
  • Not sure if I understood you correctly. What I did is (1) put my four `fol_` folders into another folder (`my_app`), (2) cd-ed to the folder that contains `my_app`, (3) in that folder, created a file `manifest.txt` containing only one line (`Main-Class: fol_d/bin/machineLearning.Demo`), and (4) executed `jar cfm my_app.jar manifest.txt my_app`. So far so good. But when I then try to run `my_app.jar` with `java -jar my_app.jar`, I get `Error: Could not find or load main class fol_d.bin.machineLearning.Demo`. – rdv Apr 03 '17 at 19:32
  • Sorry - I was too late editing my previous comment and wasn't allowed to change it anymore. What I meant is: I think I did understand you, but I ran into another problem. – rdv Apr 03 '17 at 19:40
  • @rdv I think what goes wrong in this case is that the package names didn't reflect your intermediate directory structure: the corresponding package name at the top op your `Demo.java` should be `fol_d.bin.machineLearning`, which it doesn't, if I understood the text in your question correctly. For instance, I have (Maven-structured) packages like `nl.marcelkorpel.dao` that contain classes like `DAOFactory` that contain `package nl.marcelkorpel.dao;` at the top of the file. The directory structure reflects this. Also look at http://stackoverflow.com/a/18146453/258127 – Marcel Korpel Apr 03 '17 at 23:43
  • @Stephen C - Sorry, now I'm even more confused (while I think it's really not complicated...). What exactly do you mean by 'fully qualified class name'? The class that I want to call is `Demo`, which is in the package `machineLearning`, which is in `fol_d/bin`. Does that not mean that the class name in the Main-Class attribute is `Main-Class: fol_d/bin/machineLearning.Demo`? Could you maybe provide a concrete example using my folder structure (also @Marcel Korpel)? I just fail to see where I do what wrong... – rdv Apr 04 '17 at 11:29
  • @rdv As you told me somewhere else `fol_a` to `fol_d` are project names and `machineLearning` is a package name inside such a project. Your Java source contains `package machineLearning` at the moment. However, when you try to create some kind of master project and simply copy all those folders inside it, for Java `/fol_d/bin` becomes part of the package name, so you should change it to `package fol_d.bin.machineLearning`, or, better, only copy the real package directories (within those `bin` subdirs) and then call `jar`. – Marcel Korpel Apr 04 '17 at 13:30
  • @Stephen C and Marcel Korpel - It turns out I indeed used a too complicated directory structure. In Eclipse, where I develop the code, I do this because some code should be separate from other - i.e., project A should be able to see and use project B, but not the other way around. Anyway, thanks for the help guys! – rdv Apr 08 '17 at 09:20