Alvaro Pedraza
Alvaro Pedraza

Reputation: 1292

maven build jar with dependencies

I'm working in a Maven Swing application and I'm having some issues with the building.

The environment

I'm developing my app using Netbeans 8.2 as my IDE and Jasper Reports library to generate some PDF reports based on compiled .jasper files, which are being generated separately using Jaspersoft Studio 6.3.1 and then are being used as a resource in my project.

The pom for my project is as follows (expert with relevant info):

<project>
    <!-- Needed for jasperreports-functions -->
    <repositories>
        <repository>
            <id>jr-ce-releases</id>
            <url>http://jaspersoft.artifactoryonline.com/jaspersoft/jr-ce-releases</url>
        </repository>
    </repositories>

    <dependencies>
        <dependency>
            <groupId>net.sf.jasperreports</groupId>
            <artifactId>jasperreports</artifactId>
            <version>6.4.0</version>
        </dependency>

        <dependency>
            <groupId>net.sf.jasperreports</groupId>
            <artifactId>jasperreports-functions</artifactId>
            <version>5.2.0</version>
        </dependency>

        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-all</artifactId>
            <version>2.4.12</version>
        </dependency>

        <!-- The driver I need for connecting to my DB -->
        <dependency>
            <groupId>com.ibm.informix</groupId>
            <artifactId>jdbc</artifactId>
            <version>4.10.8.1</version>
        </dependency>

        <!-- some other test dependencies -->
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.0.2</version>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>ar.edu.unt.gui.MainFrame</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>

        <!-- I exclude the Jasper XML as I only need .jasper files in my project -->
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <excludes>
                    <exclude>*.jrxml</exclude>
                </excludes>
            </resource>
        </resources>
    </build>
</project>

The problem

With this configuration, I can run the project from Netbeans by doing Right click on project -> Clean and Build option, which is equivalent to mvn clean install. The application compiles without errors and I can run it from the IDE with the Run -> Run project option from the menu and it is executed successfully. The packaged jar contains the following:

project screenshot

As you can see, the dependencies aren't being packaged within the jar. This is not desirable because I need the application to be standalone, i.e. I need to copy the jar in another computer and I must be able to run it.

To make a test I tried to run the application from the console: I moved to target/ folder and from there I run

java -jar certificado-titulos-unt-1.0.jar

And got the error

java.lang.NoClassDefFoundError: net/sf/jasperreports/engine/JRException
    at ar.edu.unt.gui.MainFrame.<init>(MainFrame.java:45)
    ...
Caused by: java.lang.ClassNotFoundException: net.sf.jasperreports.engine.JRException
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    ...

As I expected, this doesn't work as I'm outside the development environment and the dependencies are not being packaged in the jar. This is the problem

Solution attempt

I found this answer and added the maven-assembly-plugin configuration as suggested there and obtained a single jar. Apparently containing the dependencies as I didn't had the ClasNotFoundError. The problem is that with this build my code wasn't able to get some resources files conexion.properties, so this approach wasn't useful. Also, with this configuration, I wasn't able to see the package's content nor uncompress it, at least with my unzip utility.

Summarize

So, to summarize, I wasn't able to configure maven to package all my dependencies (basically, jasper-reports and groovy with transitive dependencies) within my application to overcome the ClassNotFoundError. Any help with this is highly appreciated.

Thanks in advance for your answers

Upvotes: 4

Views: 16962

Answers (1)

Brent Worden
Brent Worden

Reputation: 10974

The Shade Plugin provides the capability to create uber jars. That is, jars that contains the project's classes as well as the classes from the project's runtime dependencies.

The basic usage of the plugin is enabled by declaring the plugin in the POM's build section tying it to the package build phase:

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-shade-plugin</artifactId>
      <version>3.0.0</version>
      <executions>
        <execution>
          <phase>package</phase>
          <goals>
            <goal>shade</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

To build the uber jar, run maven with the package target

mvn package

On success, the final jar in the target directory will be the uber jar.

Upvotes: 7

Related Questions