I'm trying to get the basic HelloWorld JNA example working while using Maven to build a .jar. I'm starting with this directory structure:
.
+-- pom.xml
+-- src
+-- main
+-- java
+-- HelloWorld.java
HelloWorld.java contains the code from the JNA getting started page:
package com.sun.jna.examples;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
/** Simple example of JNA interface mapping and usage. */
public class HelloWorld {
// This is the standard, stable way of mapping, which supports extensive
// customization and mapping of Java to native types.
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary)
Native.loadLibrary((Platform.isWindows() ? "msvcrt" : "c"),
CLibrary.class);
void printf(String format, Object... args);
}
public static void main(String[] args) {
CLibrary.INSTANCE.printf("Hello, World\n");
for (int i=0;i < args.length;i++) {
CLibrary.INSTANCE.printf("Argument %d: %s\n", i, args[i]);
}
}
}
My pom.xml file contains the following:
<project>
<groupId>edu.berkeley</groupId>
<artifactId>hello-world</artifactId>
<modelVersion>4.0.0</modelVersion>
<name>Hello World</name>
<packaging>jar</packaging>
<version>1.0</version>
<properties>
<jna.version>4.5.0</jna.version>
</properties>
<dependencies>
<dependency> <!-- JNA dependency -->
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>${jna.version}</version>
</dependency>
<dependency> <!-- JNA platform dependency -->
<groupId>net.java.dev.jna</groupId>
<artifactId>jna-platform</artifactId>
<version>${jna.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.sun.jna.examples.HelloWorld</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
I can build the target .jar without problem using mvn package
, but when I try to run it I get the error mentioned in the title:
$ java -jar target/hello-world-1.0.jar
Exception in thread "main" java.lang.NoClassDefFoundError: com/sun/jna/Library
...
I can see the JNA and JNA-platform .jar files in the maven local repository. The manifest file for the built .jar has the jna related files in its class path:
$ unzip -p target/hello-world-1.0.jar META-INF/MANIFEST.MF
Manifest-Version: 1.0
Built-By: root
Class-Path: jna-4.5.0.jar jna-platform-4.5.0.jar
Created-By: Apache Maven 3.0.4
Build-Jdk: 1.8.0_144
Main-Class: com.sun.jna.examples.HelloWorld
If I manually copy the JNA .jars to the target folder, the application runs, but these .jars get removed when I do mvn clean
. I assume copying those .jars to the target directory is not correct since they are removed with a clean. What should I be doing instead to get this application to run?
EDIT:
From the link shared by Roman, I found that I need to use either the maven-assembly plugin or the maven-shade plugin. I ended up going with the maven-shade plugin and added the following to my pom.xml file:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>true</minimizeJar>
<artifactSet>
<includes>
<include>net.java.dev.jna:jna</include>
<include>net.java.dev.jna:jna-platform</include>
</includes>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
I'm using the include option so that only the white-listed dependencies (JNA) are included in order to keep the build time and .jar file size are to a minimum.