Including libraries in jar

22,274

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.

Share:
22,274
dwjohnston
Author by

dwjohnston

I like continuous integration and tight development feedback loops. Some real world problems I'm particularly interested in working with are traffic and congestion, logistics, climate change, behavioural economics, mental health and wellbeing. I also like pinball, boardgames.

Updated on July 09, 2022

Comments

  • dwjohnston
    dwjohnston almost 2 years

    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?)