1

I have a maven problem that should be easy to solve, but is proving to be a bit difficult.

I have a project that builds a jar, and needs that jar to be able to execute a class com.foo.bar.MainClass, but I need to be able to deploy it along with a few scripts and its dependencies like

some-product-1.0.0.zip
  bin/
    some-product.sh
  lib/
    some-product-1.0.0.jar
    dependency1.jar
    dependency2.jar

I can get it to make this structure quite easily. My pom.xml looks like

<plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
        <archive>
            <manifest>
                <mainClass>com.foo.bar.MainClass</mainClass>
                <addClasspath>true</addClasspath>
            </manifest>
        </archive>
        <descriptors>
            <descriptor>assembly.xml</descriptor>
        </descriptors>
    </configuration>
</plugin>

and my assembly.xml is

<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
    <id>bin</id>
    <formats>
        <format>zip</format>
    </formats>
    <files>
        <file>
            <source>src/main/scripts/some-product.sh</source>
            <outputDirectory>/bin</outputDirectory>
        </file>
    </files>
    <dependencySets>
        <dependencySet>
            <outputDirectory>/lib</outputDirectory>
            <useProjectArtifact>true</useProjectArtifact>
            <scope>compile</scope>
        </dependencySet>
    </dependencySets>
</assembly>

And some-product.sh looks like

SCRIPTLOC=$( readlink -f $( dirname "${BASH_SOURCE[0]}" ) )
LIBS="$( dirname $SCRIPTLOC )/lib"
# builds a : joined list of all the jars in the lib directory
MYCLASSES=$(echo $LIBS/*.jar | tr ' ' ':')

java -cp "$CLASSPATH:$MYCLASSES" com.foo.bar.MainClass

but what I got when I ran the script was

Exception in thread "main" java.lang.NoClassDefFoundError: com/foo/bar/MainClass
Cause by: java.lang.ClassNotFoundException com.foo.bar.MainClass
    at ...
Could not find the main class: com.foo.bar.MainClass.  Program will exit.

When I examined the jar that contains the class, the manifest only had

Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: <myname>
Build-Jdk: 1.6.0_27

telling me that it did not add the main class to the manifest.

I've googled this problem for quite some time without luck, and the examples on the assembly plugin's website are terrible. How can I get maven to build this jar correctly and add it to the zip?

EDIT: I did need the maven-jar-plugin in my pom, but my real problem was that I was using Cygwin and the classpath separator it expected was ; not :. My solution was to write some code to figure out which classpath separator to use, and with the jar plugin it works perfectly now.

mtk
  • 13,221
  • 16
  • 72
  • 112
bheklilr
  • 53,530
  • 6
  • 107
  • 163
  • Why not making your life easier and using [appassembler-maven-plugin](http://mojo.codehaus.org/appassembler/appassembler-maven-plugin/) which handles all that stuff already. It generates a script either for windows/unix and will handle all the classpath stuff for you. – khmarbaise Feb 18 '13 at 18:03

1 Answers1

3

Two things I see are

  1. The classpath is not set properly.

     SCRIPTLOC=$( readlink -f $( dirname "${BASH_SOURCE[0]}" ) )
    

    Here the SCRIPTLOC is not the root dir. It is <the_complete_path_from_root>/bin

     LIBS="$( dirname $SCRIPTLOC )/lib"
    

    This finally evaluates to <the_complete_path_from_root>/bin/lib

    And you are later adding the lib folder to it, which does not actually contain your jar. So, the correct path to be added to the classpath is lib folder where the jar is present, then it would be able to find the com.foo.bar.MainClass.

  2. For adding the Main class to the manifest file, you'll need to add the following to pom.xml file.

    <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-jar-plugin</artifactId>
         <configuration>
           <archive>
             <manifest>
               <mainClass>com.someclass.Main</mainClass>
               <packageName>com.someclass</packageName>
             </manifest>
             <manifestEntries>
                  <mode>development</mode>
                  <url>${pom.url}</url>
              </manifestEntries>
            </archive>
          </configuration>
      </plugin>
    
mtk
  • 13,221
  • 16
  • 72
  • 112
  • 1. The classpath is certainly getting set properly, I had previously put in an echo statement to make sure. The `dirname` command will get the parent directory ([see documentation](http://linux.die.net/man/1/dirname)) 2. I tried that, but I get the same error, NoClassDefFoundException – bheklilr Feb 14 '13 at 17:48
  • 1
    ok.. so it's the `maven-jar-plugin` snippet you need to add for including the main class in the manifest file. – mtk Feb 14 '13 at 17:50
  • Sorry, I had accidentally submitted my comment before finishing it (always forget that they're not multiline and hit enter). I tried that snippet, but it's still giving me the same error =/ – bheklilr Feb 14 '13 at 17:55
  • @bhek I have created a chat room, if you need to discuss http://chat.stackoverflow.com/rooms/24530/maven-assembly-jar-issue. – mtk Feb 14 '13 at 18:00