DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

SBOMs are essential to circumventing software supply chain attacks, and they provide visibility into various software components.

Related

  • AOT Compilation Make Java More Power
  • Migrating Spring Java Applications to Azure App Service (Part 1: DataSources and Credentials)
  • Aggregating REST APIs Calls Using Apache Camel
  • Realistic Test Data Generation for Java Apps

Trending

  • Stop Prompt Hacking: How I Connected My AI Agent to Any API With MCP
  • Top Load Balancing Algorithms: Choosing the Right Strategy
  • Breaking Free from ZooKeeper: Why Kafka’s KRaft Mode Matters
  • Are Traditional Data Warehouses Being Devoured by Agentic AI?
  1. DZone
  2. Coding
  3. Java
  4. Tracking Exceptions - Part 6 - Building an Executable Jar

Tracking Exceptions - Part 6 - Building an Executable Jar

By 
Roger Hughes user avatar
Roger Hughes
·
May. 09, 14 · Interview
Likes (0)
Comment
Save
Tweet
Share
9.9K Views

Join the DZone community and get the full member experience.

Join For Free

If you’ve read the previous five blogs in this series, you’ll know that I’ve been building a Spring application that runs periodically to check a whole bunch of error logs for exceptions and then email you the results. 

Having written the code and the tests, and being fairly certain it’ll work the next and final step is to package the whole thing up and deploy it to a production machine. The actual deployment and packaging methods will depend upon your own organisation's processes and procedures. In this example, however, I’m going to choose the simplest way possible to create and deploy an executable JAR file. The first step was completed several weeks ago, and that’s defining our output as a JAR file in the Maven POM file, which, as you’ll probably already know, is done using the packaging element:

     <packaging>jar</packaging>


It’s okay having a JAR file, but in this case there’s a further step involved: making it executable. To make a JAR file executable you need to add a MANIFEST.MF file and place it in a directory called META-INF. The manifest file is a file that describes the JAR file to both the JVM and human readers.

As usual, there are a couple of ways of doing this, for example if you wanted to make life difficult for yourself, you could hand-craft your own file and place it in the META-INF directory inside the project’s src/main/resources directory. On the other hand, you could use themaven-jar plug-in and do it automatically. To do that, you need to to add the following to your POM file.

       <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.4</version>
            <configuration>
                 <archive>
                     <manifest>
                           <addClasspath>true</addClasspath>
                           <mainClass>com.captaindebug.errortrack.Main</mainClass>
                           <classpathPrefix>lib/</classpathPrefix>
                      </manifest>
                 </archive>
            </configuration>
       </plugin>


The interesting point here is the <archive><manifest> configuration element. It contains three sub-elements: 

  1. addClasspath: this means that the plug-in will add the classpath to the MANIFEST.MF file so that the JVM can find all the support jars when running the app.
  2. mainClass: this tells the plug-in to add a Main-Class attribute to the MANIFEST.MF file, so that the JVM knows where to find the the entry point to the application. In this case it’s com.captaindebug.errortrack.Main
  3. classpathPrefix: this is really useful. It allows you to locate all the support jars in a different directory to the main part of the application. In this case I’ve chosen the very simple and short name of lib.


If you run the build and then open up the resulting JAR file and extract and examine the /META-INF/MANIFEST.MFfile, you’ll find something rather like this:

Manifest-Version: 1.0

Built-By: Roger
Build-Jdk: 1.7.0_09
Class-Path: lib/spring-context-3.2.7.RELEASE.jar lib/spring-aop-3.2.7.RELEASE.jar lib/aopalliance-1.0.jar lib/spring-beans-3.2.7.RELEASE.jar lib/spring-core-3.2.7.RELEASE.jar lib/spring-expression-3.2.7.RELEASE.jar lib/slf4j-api-1.6.6.jar lib/slf4j-log4j12-1.6.6.jar lib/log4j-1.2.16.jar lib/guava-13.0.1.jar lib/commons-lang3-3.1.jar lib/commons-logging-1.1.3.jar lib/spring-context-support-3.2.7.RELEASE.jar lib/spring-tx-3.2.7.RELEASE.jar lib/quartz-1.8.6.jar lib/mail-1.4.jar lib/activation-1.1.jar
Created-By: Apache Maven 3.0.4
Main-Class: com.captaindebug.errortrack.Main
Archiver-Version: Plexus Archiver


The last step is to marshall all the support jars into one directory, in this case the lib directory, so that the JVM can find them when you run the application. Again, there are two ways of approaching this: the easy way and the hard way. The hard way involves manually collecting together all the JAR files as defined by the POM (both direct and transient dependencies) and copying them to an output directory. The easy way involves getting the maven-dependency-plugin to do it for you. This involves adding the following to your POM file:

       <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <version>2.5.1</version>
            <executions>
                 <execution>
                      <id>copy-dependencies</id>
                      <phase>package</phase>
                      <goals>
                          <goal>copy-dependencies</goal>
                      </goals>
                      <configuration>
                           <outputDirectory>
                                ${project.build.directory}/lib/
                           </outputDirectory>
                      </configuration>
                 </execution>
            </executions>
       </plugin>


In this case you’re using the copy-dependencies goal executed in the package phase to copy all the project dependencies to the${project.build.directory}/lib/ directory - note that the final part of the directory path, lib, matches theclasspathPrefix setting from the previous step.

In order to make life easier, I’ve also created a small run script: runme.sh:

#!/bin/bash         

echo Running Error Tracking...
java -jar error-track-1.0-SNAPSHOT.jar com.captaindebug.errortrack.Main


And that’s about it. The application is just about complete. I’ve copied it to my build machine where it now monitors the Captain Debug Github sample apps and build. 

I could, and indeed may, add a few more features to the app. There are a few rough edges that need knocking off the code: for example is it best to run it as a separate app, or would it be a better idea to turn it into a web app? Furthermore, wouldn’t it be a good idea to ensure that the same errors aren’t reported twice?

I may get around to thart soon... or maybe I'll talk about something else; so much to blog about so little time...


The code for this blog is available on Github at: https://github.com/roghughe/captaindebug/tree/master/error-track. If you want to look at other blogs in this series take a look here… 

  1. Tracking Application Exceptions With Spring
  2. Tracking Exceptions With Spring - Part 2 - Delegate Pattern
  3. Error Tracking Reports - Part 3 - Strategy and Package Private
  4. Tracking Exceptions - Part 4 - Spring's Mail Sender
  5. Tracking Exceptions - Part 5 - Scheduling With Spring
JAR (file format) Manifest file Executable application Directory app Java (programming language) Blog Spring Framework Java virtual machine

Published at DZone with permission of Roger Hughes, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • AOT Compilation Make Java More Power
  • Migrating Spring Java Applications to Azure App Service (Part 1: DataSources and Credentials)
  • Aggregating REST APIs Calls Using Apache Camel
  • Realistic Test Data Generation for Java Apps

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • [email protected]

Let's be friends: