Ok, so here's what we've got:
We've got two library packages, which we've compiled into jars.
package starwars;
public class JarJar {
public void JarSayHello()
{
System.out.println("Jaaaaar!!");
}
}
package barwars;
public class BarBar {
public void BarSayHello()
{
System.out.println("Baaaaa!!");
}
}
We compile these with
javac -d bin -sourcepath src src/barwars/BarBar.java
jar cvf barwars.jar -C bin .
and
javac -d bin -sourcepath src src/starwars/JarJar.java
jar cvf starwars.jar -C bin .
All nicely into jars for us.
Now we want to include these two jars into another java project.
so we've got
/project/src/a_pack/HelloWorld.java
/project/libs/starwars.jar
/project/libs/barwars.jar
/project/manifest.txt
package a_pack;
import starwars.JarJar;
import barwars.BarBar;
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World");
JarJar myJar = new JarJar();
myJar.JarSayHello();
BarBar myBar = new BarBar();
myBar.BarSayHello();
}
}
Manifest.txt
Main-Class: a_pack.HelloWorld
Class-Path: libs/starwars.jar libs/barwars.jar
Now we compile this with:
javac -d bin -sourcepath src -cp "libs/starwars.jar;libs/*" src/a_pack/HelloWorld.java
jar cvfm helloworld.jar manifest.txt -C bin .
And this compiles and runs fine.
Now I have two problems.
Firstly - if I move this jar file to somewhere else, and try run it, then I'll get:
Exception in thread "main" java.lang.NoClassDefFoundError: starwars/JarJar
Now I can fix this by moving the libs folder to wherever I move the jar. But this strikes me as messy (what if there is already a libs folder in that location?).
Ideally what I'd like to do, is include the referenced jars inside the jar, so there's one jar that contains everything that's required to run inside itself.
Is this possible? (And is it good practise?)
Possible, yes. Good practice, no.
Jars are just zip files, so you can unzip and rezip to your heart's content. The bigger problem is managing all of these separate jars as your project gets larger.
Most projects do not compile using the command line. Instead, an IDE keeps your jars up to date. And most modern Java projects use Maven or Ivy to place jars in a repository and fish them out as needed.
Look at Eclipse, Netbeans, or Intellij for IDEs. And look into Maven for structuring your project.
Related
How can I import file from outside of package?
example:
// this is a.java
package user.code.gui;
void method_a(){
// do something
}
and
// this is b.java
package user.code;
void method_b(){
// do something
}
and
// this is c.java
package user.extensions;
void method_c(){
// do something
}
If I use "import c" in file a.java, it can't find this file because it's in a different package. The problem is, how can I import file c.java in file a.java?
You need the other package to be there during compilation, and also during runtime; these are different things, but they both have the concept of a classpath.
Java always looks for things by translating type names to dir names; package a.b; class Foo {} is looked for in /a/b/Foo.class.
It scans each entry in the classpath for that. Classpath entries can be either directories, or jar files.
Build systems (maven, gradle, etc) and IDEs (eclipse, intellij, etc) - make this easily configurable and in general take care of it for you. You should use these tools; 99% of all java projects are compiled by IDEs and/or build tools.
Once you start having multiple packages, javac becomes unwieldy.
But, if you must use the command line for it:
Your directory structure:
/Users/Cflowe/workspace/MyAwesomeProject/src/user/code/gui/GuiClass.java
/Users/Cflowe/workspace/MyAwesomeProject/src/user/code/Whatever.java
and so on. To compile:
cd /Users/Cflowe/workspace/MyAwesomeProject
mkdir bin
javac -sourcepath src -d bin src/user/code/Whatever.java src/user/code/gui/GuiClass.java andSpecifyEveryOtherFileByHandHere
java -cp bin com.foo.Main
Been looking for around 2 hours for a solution to my problem, tried countless solutions and still the problem remains unsolved.
I have a game project with few packages; geometry, levels, decoration, and game. Inside the game package resides a gameRun.java
package game;
public class gameRun {
/**
* Program entry point.
* #param args the arguments for the levels
*/
public static void main(String args[]) {
... some code
}
}
and I have the following manifest file :
Main-Class: game.gameRun
Class-Path: someExternalGraphicTool.jar
//newline here
I compile my whole game using the following command : (the bin folder already exists).
javac -d bin src/geometry/*.java src/decoration/*.java src/levels/*.java src/game/*.java
I then turn my compiled classes into an executable .jar file using the command :
jar cvfm t.jar manifest.mf bin/geometry/*.class bin/decoration/*.class bin/levels/*.class bin/game/*.class
I then try to run my t.jar using :
java -jar t.jar
//or
java -cp .:t.jar game.gameRun
which both produce the error, "Error: Could not find or load main class game.gameRun"
However, when I unzip the jar file, inside the bin/game directory I can see a gameRun.class file and inside the META-INF\MANIFEST.MF file I can still see that the Main-Class is set to game.gameRun.
Note that I am working on a remote linux server, on a command line, and the jar file doesn't work even if I download it to my windows 10 machine.
What did I do wrong during this process ? Thanks for any help.
Your classes are in a wrong structure inside a jar file, because of the bin folder. My suggestion: pack it all into a jar starting in a bin folder.
Now when you extract your jar you will see 2 folders: META-INF and bin.
If you make the jar from bin folder you will see: META-INF and game, and it will work.
It doesn't work for you simply, because it can't find the main class, since it is inside the bin/game/YourClass.class, not in game/YourClass.class.
...\bin> jar cvfm t.jar manifest.mf geometry/*.class decoration/*.class levels/*.class game/*.class
And then just:
...\bin> java -jar t.jar
I've been trying to run a app from a Jarfile, but it keeps printing out:
"cannot find or load main class ...".
I tried to solve this problem using infos from this thread but all seemed to be useless. To be honest, I'm getting desperate because of the fact that this is such a trivial problem.
Anyways, what I did:
Main-Class: com.test.Test
my manifest attribute:
jar cfm test.jar manifest.txt <full_path>/out/com/test/*.class
which is what's packaged into the jar file (the Test.class file)
The Test class:
package com.test;
public class Test {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
You should package the class correctly. Do
jar cfm test.jar manifest.txt com/test/*.class
in the parent folder of the folder com. By providing the absolute path (the way you did), the class file is packaged incorrectly.
Firstly, just in case you are using Eclipse IDE, there is some tools like the Fat Jar Plugin which are able to help you to package your build.
Secondly, there is Maven, to handle your dependencies, and build the package you need with everything ok. In your case, I will look for the Apache Maven Jar Plugin.
Finally, the old school way to go with the commandline, as you tried to do.
As Eliott Frisch has said in your question comments, you don't need to provide the fullpath to the mainclass inside your jar cfm test.jar manifest.txt <full_path>/out/.
And what's because the manifest.txt already give the package information!
I'm trying to figure out how an existing Java program (I did not make myself ofcourse) was compiled with existing jars
I have Test.java (original source file):
package Demo;
//import classes from jars here etc...
public class Test {
public static void main(String args[]) {
etc...
}
}
Now I have two other jars:
file1.jar
file2.jar
Demo.jar
There is a batch script to run it:
#echo off
set CLASSPATH="file1.jar";"file2.jar";"Demo.jar"
java -cp %CLASSPATH% Demo.Test
This WORKS, but now I need to change the source file Test.java, recompile and run with the jars class dependencies. (sorry if I'm not making sense)
Now, I have tried to recompile this to reproduce same results with no luck:
javac -cp file1.jar;file2.jar;Demo.jar Test.java
defined manifest:
manifest.mf
Main-class: Demo.Test
Created directory "store" for class files and moved class files there
Ran:
jar -cmf manifest.mf Demo.jar store
Which created the "Demo.jar"
Then I ran the run the batch script above but not the same results (doesn't work at all)
Any help would be appreciated. Thank you!
It is difficult to create true executable jars as soon as you rely on external jars.
The only solution here is to :
put all jars in the same folder : yours and its dependencies
add a classpath entry inside your manifest
launch the jar using java -jar Demo.jar
The manifest will have to look like :
manifest.mf
Main-class: Demo.Test
Class-Path: file1.jar file2.jar
I'm trying to create an executable jar from the command line. The main class in the JAR has dependencies that i have packaged into another plain JAR file.
I want to package the dependency JAR together with the executable JAR in order to have a single JAR file to ship.
What i have tried so far is the following:
The dependency Hello.class file has the mock code:
public class Hello {
public String getHello() {
return "Well hello there!!";
}
}
I have packaged class file into hello.jar using:
jar cvfM hello.jar Hello.class
The hello.jar content is now:
hello.jar -+- Hello.class
Now i have the main class with the mock code:
public class Main {
public static void main(String[] args) {
System.out.println(new Hello().getHello());
}
}
I then create a manifest file manifest.txt with the following content:
Main-Class: Main
Class-Path: hello.jar
I now create the executable JAR using:
jar cvfm main.jar manifest.txt Main.class hello.jar
The main.jar content is now:
main.jar -+- Main.class
|
+- hello.jar
|
+- META-INF -+- MANIFEST.MF
Running the executable JAR using:
java -jar main.jar
I get a class loader error for the Hello class dependency. I understand that this is because the class loader looks for hello.jar in the same path as main.jar. So when i put a copy of hello.jar alongside main.jar i am able to run it.
What do i need to do in order to be able to run main.jar with hello.jar inside of it?
I know that you will ask: "why is he trying to do it this way?". I know that ppl mostly use Eclipse, Ant, Maven or other tools to do this. But please just humor me :)
Your approach is completely wrong unfortunately.
There is no "normal" way to place a jar inside of another jar. So your hello.jar has nothing to do inside of main.jar! The point is the "normal" classloader wont look for jar files inside of jars, hence you get the class not found error.
However: if you want desparetly to do that, then google for "OneJar" and go to http://one-jar.sourceforge.net/
There's no easy way to do this. That is, you are going to have to write your own classloader if you want to nest jars inside a jar.
There are several products out there that already support this for you. One-Jar is one of them that I've used with a lot of success -- can easily ant script it.
Here is an interesting SO discussion on the whole topic --
Easiest way to merge a release into one JAR file
Well, I believe you may be facing a jar generation bug. Check out this link, it might enlight you.
A teaser:
As far as I aware, and based on my own attempts, there's no
way to specify a Class-Path that makes the class loader
look in embedded jar files. See the preceeding paragraph
for a description.
Therefore, you may check one of the following links:
classpath-including-jar-within-a-jar, java-easiest-way-to-merge-a-release-into-one-jar-file
Cheers!