Building executable jar with maven?

157,618

Solution 1

Actually, I think that the answer given in the question you mentioned is just wrong (UPDATE - 20101106: someone fixed it, this answer refers to the version preceding the edit) and this explains, at least partially, why you run into troubles.


It generates two jar files in logmanager/target: logmanager-0.1.0.jar, and logmanager-0.1.0-jar-with-dependencies.jar.

The first one is the JAR of the logmanager module generated during the package phase by jar:jar (because the module has a packaging of type jar). The second one is the assembly generated by assembly:assembly and should contain the classes from the current module and its dependencies (if you used the descriptor jar-with-dependencies).

I get an error when I double-click on the first jar:

Could not find the main class: com.gorkwobble.logmanager.LogManager. Program will exit.

If you applied the suggested configuration of the link posted as reference, you configured the jar plugin to produce an executable artifact, something like this:

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
      <archive>
        <manifest>
          <addClasspath>true</addClasspath>
          <mainClass>com.gorkwobble.logmanager.LogManager</mainClass>
        </manifest>
      </archive>
    </configuration>
  </plugin>

So logmanager-0.1.0.jar is indeed executable but 1. this is not what you want (because it doesn't have all dependencies) and 2. it doesn't contain com.gorkwobble.logmanager.LogManager (this is what the error is saying, check the content of the jar).

A slightly different error when I double-click the jar-with-dependencies.jar:

Failed to load Main-Class manifest attribute from: C:\EclipseProjects\logmanager\target\logmanager-0.1.0-jar-with-dependencies.jar

Again, if you configured the assembly plugin as suggested, you have something like this:

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
      <descriptorRefs>
        <descriptorRef>jar-with-dependencies</descriptorRef>
      </descriptorRefs>
    </configuration>
  </plugin>

With this setup, logmanager-0.1.0-jar-with-dependencies.jar contains the classes from the current module and its dependencies but, according to the error, its META-INF/MANIFEST.MF doesn't contain a Main-Class entry (its likely not the same MANIFEST.MF as in logmanager-0.1.0.jar). The jar is actually not executable, which again is not what you want.


So, my suggestion would be to remove the configuration element from the maven-jar-plugin and to configure the maven-assembly-plugin like this:

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <version>2.2</version>
    <!-- nothing here -->
  </plugin>
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <version>2.2-beta-4</version>
    <configuration>
      <descriptorRefs>
        <descriptorRef>jar-with-dependencies</descriptorRef>
      </descriptorRefs>
      <archive>
        <manifest>
          <mainClass>org.sample.App</mainClass>
        </manifest>
      </archive>
    </configuration>
    <executions>
      <execution>
        <phase>package</phase>
        <goals>
          <goal>single</goal>
        </goals>
      </execution>
    </executions>
  </plugin>

Of course, replace org.sample.App with the class you want to have executed. Little bonus, I've bound assembly:single to the package phase so you don't have to run assembly:assembly anymore. Just run mvn install and the assembly will be produced during the standard build.

So, please update your pom.xml with the configuration given above and run mvn clean install. Then, cd into the target directory and try again:

java -jar logmanager-0.1.0-jar-with-dependencies.jar

If you get an error, please update your question with it and post the content of the META-INF/MANIFEST.MF file and the relevant part of your pom.xml (the plugins configuration parts). Also please post the result of:

java -cp logmanager-0.1.0-jar-with-dependencies.jar com.gorkwobble.logmanager.LogManager

to demonstrate it's working fine on the command line (regardless of what eclipse is saying).

EDIT: For Java 6, you need to configure the maven-compiler-plugin. Add this to your pom.xml:

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
      <source>1.6</source>
      <target>1.6</target>
    </configuration>
  </plugin>

Solution 2

The answer of Pascal Thivent helped me out, too. But if you manage your plugins within the <pluginManagement>element, you have to define the assembly again outside of the plugin management, or else the dependencies are not packed in the jar if you run mvn install.

<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">
    <modelVersion>4.0.0</modelVersion>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>jar</packaging>


    <build>
        <pluginManagement>
            <plugins>

                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.1</version>
                    <configuration>
                        <source>1.6</source>
                        <target>1.6</target>
                    </configuration>
                </plugin>

                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-assembly-plugin</artifactId>
                    <version>2.4</version>
                    <configuration>
                        <archive>
                            <manifest>
                                <mainClass>main.App</mainClass>
                            </manifest>
                        </archive>
                        <descriptorRefs>
                            <descriptorRef>jar-with-dependencies</descriptorRef>
                        </descriptorRefs>
                    </configuration>
                    <executions>
                        <execution>
                            <id>make-assembly</id>
                            <phase>package</phase>
                            <goals>
                                <goal>single</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>

            </plugins>

        </pluginManagement>

        <plugins> <!-- did NOT work without this  -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
            </plugin>
        </plugins>

    </build>


    <dependencies>
       <!--  dependencies commented out to shorten example -->
    </dependencies>

</project>

Solution 3

If you don't want execute assembly goal on package, you can use next command:

mvn package assembly:single

Here package is keyword.

Share:
157,618
RMorrisey
Author by

RMorrisey

Updated on September 14, 2020

Comments

  • RMorrisey
    RMorrisey over 3 years

    I am trying to generate an executable jar for a small home project called "logmanager" using maven, just like this:

    How can I create an executable JAR with dependencies using Maven?

    I added the snippet shown there to the pom.xml, and ran mvn assembly:assembly. It generates two jar files in logmanager/target: logmanager-0.1.0.jar, and logmanager-0.1.0-jar-with-dependencies.jar. I get an error when I double-click on the first jar:

    Could not find the main class: com.gorkwobble.logmanager.LogManager. Program will exit.
    

    A slightly different error when I double-click the jar-with-dependencies.jar:

    Failed to load Main-Class manifest attribute from: C:\EclipseProjects\logmanager\target\logmanager-0.1.0-jar-with-dependencies.jar
    

    I copied and pasted the path and classname, and checked the spelling in the POM. My main class launches fine from an eclipse launch configuration. Can someone help me figure out why my jar file won't run? Also, why are there two jars to begin with? Let me know if you need more information.

    Here is the full pom.xml, for reference:

    <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/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>com.gorkwobble</groupId>
      <artifactId>logmanager</artifactId>
      <name>LogManager</name>
      <version>0.1.0</version>
      <description>Systematically renames specified log files on a scheduled basis. Designed to help manage MUSHClient logging and prevent long, continuous log files.</description>
      <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>2.2</version>
                <!-- nothing here -->
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.2-beta-4</version>
                <configuration>
                  <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                  </descriptorRefs>
                  <archive>
                    <manifest>
                      <mainClass>com.gorkwobble.logmanager.LogManager</mainClass>
                    </manifest>
                  </archive>
                </configuration>
                <executions>
                  <execution>
                    <phase>package</phase>
                    <goals>
                      <goal>single</goal>
                    </goals>
                  </execution>
                </executions>
              </plugin>
              <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                  <source>1.6</source>
                  <target>1.6</target>
                </configuration>
              </plugin>
        </plugins>
      </build>
      <dependencies>
        <!-- commons-lang -->
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.4</version>
        </dependency> 
    
        <!-- Quartz scheduler -->
        <dependency>
            <groupId>opensymphony</groupId>
            <artifactId>quartz</artifactId>
            <version>1.6.3</version>
        </dependency>
        <!-- Quartz 1.6.0 depends on commons collections -->
        <dependency>
          <groupId>commons-collections</groupId>
          <artifactId>commons-collections</artifactId>
          <version>3.1</version>
        </dependency>
        <!-- Quartz 1.6.0 depends on commons logging -->
        <dependency>
          <groupId>commons-logging</groupId>
          <artifactId>commons-logging</artifactId>
          <version>1.1</version>
        </dependency>
        <!-- Quartz 1.6.0 requires JTA in non J2EE environments -->
        <dependency>
          <groupId>javax.transaction</groupId>
          <artifactId>jta</artifactId>
          <version>1.1</version>
          <scope>runtime</scope>
        </dependency>
    
        <!-- junitx test assertions -->
        <dependency>
            <groupId>junit-addons</groupId>
            <artifactId>junit-addons</artifactId>
            <version>1.4</version>
            <scope>test</scope>
        </dependency>
    
        <!-- junit dependency; FIXME: make this a separate POM -->
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.1</version>
        </dependency>
    
      </dependencies>
      <dependencyManagement>
      </dependencyManagement>
    </project>
    
  • RMorrisey
    RMorrisey over 14 years
    Thanks for your comments! I changed my pom.xml as you specified. When I run mvn clean install, I get a bunch of compilation errors from my code, saying that annotations and so on are not supported in -source 1.3. I am using jdk1.6 and it compiles in eclipse; I'm not sure how the 1.3 got introduced. Maybe one of the library versions in the pom snippet is an older one?
  • RMorrisey
    RMorrisey over 14 years
    Thanks! I got past the 1.3 issue. I also had to add the junit4 dependency to my POM. I'm working on troubleshooting other stuff; if I get stuck I'll post again! If I get the jar running I'll mark this as answer. My current POM is updated in the question above.
  • Admin
    Admin over 13 years
    Is there any way to exclude the resources from the generated jar file?
  • Devanshu Mevada
    Devanshu Mevada over 13 years
    @HaiMinhNguyen Which jar? The default one or the one generated by the assembly plugin? In both cases, it's possible but not exactly the same way.
  • Admin
    Admin over 13 years
    The one generated by the assembly plugin. I've found a way thanks to your answer here stackoverflow.com/questions/2737601/…. Thanks.
  • Admin
    Admin over 13 years
    @Pascal Thivent: Sorry I think I'm wrong. I've asked a question about my problem (stackoverflow.com/questions/4113697/…). Could you please help me? Thank you very much.
  • Funky coder
    Funky coder over 12 years
    Nice answer, but I have a small problem with my assembly. When I switch appendAssemblyId to false, I have my classes doubled in my outpu jar file! Any idea how to fix this? I assume that assembly plugin would normally create a new jar file with "-jar-with-dependencies" suffix, but since I switched it off it appends dependencies together with project files in the existing jar (created with jar:jar)
  • saravana_pc
    saravana_pc almost 12 years
    @Pascal, as per the above approach, the dependent jars are in exploded format inside my jar. Is it possible to retain the dependencies as jars (within my jar) ?
  • Adam Parkin
    Adam Parkin over 11 years
    If I could give more than one upvote on this I so would. Thank you so much as the other answer simply did not work for me.
  • Daniil Shevelev
    Daniil Shevelev over 10 years
    Is it possible to have resulting jar to have a "normal" name?
  • Daniil Shevelev
    Daniil Shevelev over 10 years
    To answer my own comment: using "shade" plugin with "transformers" property works for changing the name of the produced jar.
  • Admin
    Admin about 9 years
    I also found this Sonatype blog post useful
  • shashaDenovo
    shashaDenovo almost 9 years
    Thanks Mike, It helped me. Initially my package was getting generated without using <pluginManagement>. But Eclipse was giving some error in pom.xml "maven - Plugin execution not covered by lifecycle". Which distract me. So to solve this i added <pluginManagement>, now the eclipse error gone but my package stopped being build. Your above snippet of pom has worked for me. :)
  • ininprsr
    ininprsr almost 9 years
    This was useful.. while using <pluginManagement>, the top answer won't work.