11

My maven project is like this and I have a quartz.properties file in /src/main/resources folder as shown below

my-app
|-- pom.xml
`-- src
    |-- main
    |   |-- java
    |   |   `-- com
    |   |       `-- mycompany
    |   |           `-- app
    |   |               `-- App.java
    |   `-- resources
    |       `-- quartz.properties
    `-- test
        |-- java
            `-- com
                `-- mycompany
                    `-- app
                        `-- AppTest.java

Now I want to make an executable jar using maven so that I can run it like this java -jar abc.jar. Below is my main method code which works fine in my laptop in my eclipse IDE but I want to run it on my ubuntu machine using java -jar command:

public static void main(String[] args) {
    StdSchedulerFactory factory = new StdSchedulerFactory();
    try {
        factory.initialize(App.class.getClassLoader().getResourceAsStream("quartz.properties"));
        Scheduler scheduler = factory.getScheduler();
        scheduler.start();
    } catch (SchedulerException ex) {
        System.out.println("error= " + ExceptionUtils.getStackTrace(ex));
    }
}

And here is my pom.xml file as of now. What changes I need to have in my pom.xml file to make an executable jar so that I can run it with java -jar?

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <parent>
        <groupId>com.host.domain</groupId>
        <artifactId>DataPlatform</artifactId>
        <version>4.2.8-RELEASE</version>
    </parent>

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mycompany.app</groupId>
    <artifactId>abc</artifactId>
    <version>1.0.0</version>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.2.1</version>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz-jobs</artifactId>
            <version>2.2.1</version>
        </dependency>
        <dependency>
            <groupId>javax.transaction</groupId>
            <artifactId>jta</artifactId>
            <version>1.1</version>
        </dependency>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.3.1</version>
        </dependency>
    </dependencies>
</project>
user1950349
  • 4,738
  • 19
  • 67
  • 119

3 Answers3

17

You can configure maven jar plugin to achieve this.

Try adding following just above dependencies section:

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <configuration>
          <archive>
            <manifest>
              <addClasspath>true</addClasspath>
              <mainClass>com.mycompany.app.App</mainClass>
            </manifest>
          </archive>
        </configuration>
      </plugin>
    </plugins>
  </build>

Here, <addClasspath>true</addClasspath> will add classpath entries to the manifest of your jar, so as long as you have those jars in same directory, your application will run fine.

You can customize the library path with, for example, <classpathPrefix>lib/</classpathPrefix>. It means your libraries should be placed in relative /lib directory.

You can also use maven dependency plugin if you want to automatically copy your libraries to output directory.

Amila
  • 5,195
  • 1
  • 27
  • 46
  • Thanks. Do I need `maven-dependency-plugin` as well? I have dependency on various other libraries as well some open source and some internal. – user1950349 Sep 14 '15 at 06:39
  • something is weird, I tried your way and I did `mvn clean install` which generated a jar file and I used that file and ran it and I got this error `java.lang.NoClassDefFoundError ` ----- `Exception in thread "main" java.lang.NoClassDefFoundError: org/quartz/SchedulerException at java.lang.Class.getDeclaredMethods0(Native Method)`. – user1950349 Sep 14 '15 at 07:08
  • Only difference is - I also have `maven-eclipse-plugin` in my pom.xml file. – user1950349 Sep 14 '15 at 07:09
  • I do have a maven dependency for QuartzScheduler in my pom.xml. – user1950349 Sep 14 '15 at 07:10
  • May be this line is causing problem. I have something like this `dependency-jars/` – user1950349 Sep 14 '15 at 07:11
  • that line means, you should place all your library jars in a subdirectory named "dependency-jars". have you done so? – Amila Sep 14 '15 at 07:23
  • I just added it but I am getting above error. I don't know why. – user1950349 Sep 14 '15 at 07:24
  • Do I need to use `maven-shade-plugin` here? – user1950349 Sep 14 '15 at 07:42
  • No need to use shade plugin if your libraries are correctly located. Exact your jar and see MANIFEST.MF file has a line similar to: Class-Path: dependency-jars/lib1.jar dependency-jars/lib2.jar – Amila Sep 14 '15 at 07:50
  • Yes I do see that jar. I started using lib so I see this - `lib/quartz-2.2.1.jar` and `lib/quartz-jobs-2.2.1.jar` – user1950349 Sep 14 '15 at 08:00
  • @user1950349 can you update your question with your output directory structure and the way you're executing your program? – Amila Sep 14 '15 at 08:58
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/89601/discussion-between-user1950349-and-amila). – user1950349 Sep 14 '15 at 14:53
2

Actually you'll just need to add

<packaging>jar</packaging>

to your header, In other words:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

  <parent>
    <groupId>com.host.domain</groupId>
    <artifactId>DataPlatform</artifactId>
    <version>4.2.8-RELEASE</version>
  </parent>

  <modelVersion>4.0.0</modelVersion>
  <groupId>com.mycompany.app</groupId>
  <artifactId>abc</artifactId>
  <version>1.0.0</version>
<!-- This is where the magic happens -->
  <packaging>jar</packaging>

Then when you invoke on the command line make sure you include the fully qualified name of your class, like this:

java -cp NameOfFile.jar com.mycompany.app.App

The advantage of this is that you can multiple class files with main() methods that can be executed in one .jar file.

You can also include the suggestion of @Amila so you don't have to include the name when executing the jar, but you'll have to use this syntax instead:

java -jar NameOfFile.jar

Craig
  • 2,286
  • 3
  • 24
  • 37
0

depending on what will end up in the jar file or what is required to run it it is probably not that easy. There is a good collection here: How can I create an executable JAR with dependencies using Maven?

I would add Spring-Boot to that list. They have created a maven plugin to achieve this including a classloader that can read jar files inside a jar file.

There is also the maven shade plugin. Depending on what you do that might just work or it may get cumbersome (if there are signed jars for example).

Community
  • 1
  • 1
wemu
  • 7,952
  • 4
  • 30
  • 59