Sunday, August 21, 2016

Java 8: How to create executable fatJAR withouch IDE :: command-line : explained

  The executable fatJAR (fat Java ARchive) is pretty handy thing. Besides the fact that it can be quite big, it contains all necessary libraries to execute the developed program. 
The JAR file is based on ZIP format.
  In the previous posts:
a.  "Java 8 : How to create executable JAR without IDE, command-line :: explained"
b.  "Java 8 : How to create executable JAR without IDE with packages, command-line :: explained
we have explained how we handle pure JAVA project without any external libraries with or without complicated package structure. 
  The goal of current post is to create fatJAR file. The JAR which contains all necessary external libraries. Let's start slowly by creating new pure java project over the command line. We call it 
"Executable-Two" (GitHub)
  The executable-two project has following folder structure:
./ExecutableTwo.jar
./libs
./libs/ExecutableOne.jar
./out
./README.md
./src
./src/main
./src/main/java
./src/main/java/com
./src/main/java/com/exec
./src/main/java/com/exec/two
./src/main/java/com/exec/two/Main.java
./src/main/resources
./src/main/resources/META-INF
./src/main/resources/META-INF/MANIFEST.MF
  The folder LIBS contains previously created JAR file "ExecutableOne.jar". 
The "ExecutableOne.jar" contains the MagicService class which we will use inside the project "ExecutableTwo". We will instantiate the class MagicService and execute the public method getMessage(). All this will happen inside the Main class of the project "ExecutableTwo". Let's create following Main class in the project 
package com.exec.two :
1 package com.exec.two;                                                                                                                                                                  
2                                                                                                                                                                                        
3 import com.exec.one.service.MagicService;                                                                                                                                              
4                                                                                                                                                                                        
5 public class Main {                                                                                                                                                                    
6                                                                                                                                                                                        
7     public static void main(String[] args){                                                                                                                                            
8                                                                                                                                                                                        
9         System.out.println("Executable-Two Main");                                                                                                                                     
10         MagicService service = new MagicService();                                                                                                                                     
11         System.out.println("MagicService from Executable-ONE");                                                                                                                        
12         System.out.println("MESSAGE: " + service.getMessage());                                                                                                                        
13                                                                                                                                                                                        
14     }                                                                                                                                                                                  
15                                                                                                                                                                                        
16 }
   Now we have everything ready for fatJAR file creation. We have imported MagicService from the jar library we have previously created and we have executed it's getMessage() method. 
For the next steps we will use javac and jar tools provided by Java JDK. Let's open the command line and compile the project. In the command we need to inform the compiler that we should extend its classpath about the used library.
$javac -cp ./src/main/java 
./src/main/java/com/exec/two/*.java -d ./out/ 
-classpath ./libs/ExecutableOne.jar
  The "Executable-Two" project has been successfully compiled into the OUT directory.
Now it's time to properly prepare OUT directory for fatJAR creation. Inside the directory are available only compiled class we have created for project "Executable-Two". We will use again for JAR file creation jar tool, but the problem is that jar tool reads only the file physically located on the filesystem. The jar tool won't read compressed jar file. 
It means even when we copy the ExecutableOne.jar into the OUT directory jar tool will not unpack the ExecutableOne.jar file and the library will be add to the result but ignored.

   The problem is that $java -jar tool does not read inner packaged *.jar archive files!  

  It implies that we need to unpack previously created Java Archive (JAR) "Executable-One.jar" into the "Executable-Two" project OUT directory.
Open the command line and type: 
$cp libs/ExecutableOne.jar ./out/
$cd ./out
$tar xf ExecutableOne.jar
$rm ExecutableOne.jar 
  Used JAR tool command options: x - extract, f - file
  Now  "Executable-Two" project output directory OUT is ready to be used as the source folder for the new JAR file.
NOTE: inside every executable jar file is only one MANIFES.FM file available.
  For packing our "Executable-Two" project into the JAR archive file we do use newly created manifest file located in the folder ./src/main/resources/META-INF/ :
1 Manifest-Version: 1.0                                                                                                                                                                  
2 Class-Path: .                                                                                                                                                                          
3 Main-Class: com.exec.two.Main   
and now we can pack all together by typing:
$jar cvfm ExecutableTwo.jar ./src/main/resources/META-INF/MANIFEST.FM -C./out/ .
  When we executed the created fatJAR file we received following output:
$java -jar ./ExecutableTwo.jar
output:
Executable-Two Main
MagicService from Executable-ONE
MESSAGE: Magic Message
  Now we have achieved the GOAL and we have created "Executable-two.jar" executable fat Java Archive.
Congratulation!

No comments: