How to load a native API with JNA - java

I am developping in java for five years and I am also using Maven for almost five years.
I am currently working on a proximity chat project in order to get some knowledge about multi-threading, network, SourceDataline and TargetDataline. For bandpass optimization I need to find a way to encode the bytes array that represents a samples coming from the microphone.
I know that Mumble already propose this technology but I want to do it by myself even if it will not be as efficient. In the wiki it is written that the software is based on Audio codec which is written in C.
So that is the first time for me to use native code and therefore that is the first time I have to work with JNA.
THE PROBLEM: I am not able to load the library.
For flexibility, the all project is divided into several sub project listed here from the lowest layer to the higher:
communication: send/receive asynchronously byte from the network.
messenger: structure a message to send to the remote.
mumble-common: Gather the request a client can send to the remote or the server can send to each client. It depends on the projects communication and messenger.
sound: Simplify access to the microphone and speakers. It is this project that will integrate the dll in order to optimize the bandpass.
mumble-client: Package to send data to the server without knowing the message structure. It depends on the projects mumble-common and sound.
mumble-client-gui: It is the jar the final user use. It depends on the project mumble-client.
To work with audio codec in java, I found this project which is a java wrapper for the native dll. I added this project as dependency for my sound project (Adding the repositories and dependency maven tag in the pom). However when I try to run the mumble-client-gui from the IDE, I got this error :
java.lang.UnsatisfiedLinkError: Unable to load library 'opus': Native library (win32-x86-64/opus.dll) not found in resource path [resource path list]
Until now, this is what I tried :
Update the class path of sound from Eclipse but first I got the same error and second I had to furnish a absolute path which is not what I want to do because the project will be deployed on several machines.
Use maven-nativedependencies-plugin but I did not get a big changes.
Integrate the dll directly in my sound project using JNA but it throws an exception because the dll is not registered in the class path.
Copy/past the dll into a known Directory and load it using :
System.load("absolute/path/to/library")
but I got another exception : The dll is in 32 bit whereas the JVM is in 64 bit but the dll is really in 64 bit. For me that is a secondary issue if I can load and use the dll directly with JNA (using the already implemented java wrapper or using directly JNA and the dll manually).
So right now I have absolutely no idea of what I am missing..
The solution I am looking for should respects the following criteria:
It should works if mumble-client-gui is running from the IDE or from the jar and if I have to modify the resource path, I'd rather to precise a relative path.
Feel free to ask for more details and for source code ! :)
Here is the pom.xml of the sound project :
<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>fr.pederobien</groupId>
<artifactId>sound</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>sound</name>
<url>http://maven.apache.org</url>
<properties>
<author>Pierre-Emmanuel41</author>
<project.build.sourceEncoding>Cp1252</project.build.sourceEncoding>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
</properties>
<repositories>
<repository>
<id>tomp2p.net</id>
<url>http://tomp2p.net/dev/mvn/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>fr.pederobien</groupId>
<artifactId>utils</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>net.tomp2p</groupId>
<artifactId>opus-wrapper</artifactId>
<version>1.3</version>
</dependency>
</dependencies>
<build>
<finalName>sound</finalName>
<sourceDirectory>src/main/java</sourceDirectory>
<resources>
<resource>
<targetPath>./src/main/resources/natives</targetPath>
<filtering>true</filtering>
<directory>${basedir}/src/main/resources/natives</directory>
<includes>
<include>libopus.dll</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>src</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

You don't need any maven configuration as that's mostly for the JVM itself and won't impact JNA's library loading. You can configure the JNA search paths from Java, though, at your program start-up.
From the JNA javadocs, you can set jna.library.path to the directory you want to search for all DLLs. This will be searched in addition to platform-specific search locations for system DLLs.
System.setProperty("jna.library.path", "your/path/here");
Alternately you could set a search for a specific library with addSearchPath()
NativeLibrary.addSearchPath("opus", "your/path/here");

Okay based on the solution proposed by Daniel Widdis,
I put this code :
NativeLibrary.addSearchPath("opus", "src/main/resources/win32-x86-64/opus.dll");
into a static block of the ExternalEncoder, the class that will use directly the java wrapper. In that case the library is loaded only once.
It seems working because I don't get any error by now. But I found something strange that maybe you can explain to me :
I am using eclipse and when I save the ExternalEncoder, then in my folder "\target\classes" it creates the directory win32-64-x86 with the dll inside. When I delete it, remodify ExternalEncoder and save it, then the directory is recreated.
Where it comes from ? From Eclipse ? From Maven ? The win32-64-x86 directory name ?

Related

JavaFX in Codenvy using Maven, is it possible?

I've spent the entirety of yesterday and the start of today trying to find out why Codenvy is using Java 8, but cannot find the JavaFX library that is included with it. I've looked through the files of the machine and cannot find it anywhere. I've also attempted to add it natively as a Source jar, but Codenvy seems to have removed support for this. On top of this, their tutorial page for adding source jars has been replaced with how to set up Che. I just use the Codenvy website and keep everything on the cloud.
So my problem is that I cannot get sound (MP3) to play. I tried the project on a workspace I set up in Codenvy previously, and it worked without an issue... yet a workspace made post Codenvy Beta release doesn't work, the JavaFX library just isn't there. The workspace from the older Codenvy doesn't have a stack (see below). Where as the newer projects do. I've tried workspaces with all the stacks that include Java, and still nothing. I did put the project into the old workspace and it worked flawlessly, but the old workspace doesn't have all the features of the newer ones, like ctrl+space for auto-complete, ect. I may aswell be using Notepad.
Is anyone else experiencing this, and is there a way to fix it?
Below is also my pom.xml so you can see the configuration.
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>TMMOJ</groupId>
<artifactId>TMMOJ</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<build>
<plugins>
<plugin>
<!-- Build an executable JAR -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<argLine>-Xmx1024m</argLine>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>Main</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<verbose>true</verbose>
<fork>true</fork>
<compilerVersion>1.5</compilerVersion>
</configuration>
</plugin>
</plugins>
Managed to get this working by adding the jfxrt.jar from the JDK .tar.gz from the official java website to a lib folder, and adding it as a dependency (as described in one of the answers to this question JavaFX 2 as a Maven dependency). This solved the problem.

Maven annotation processing processor not found

I'm new to annotation processing and I'm trying to automating it with Maven. I've put this in my pom.xml:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<annotationProcessors>
<annotationProcessor>
co.aurasphere.revolver.annotation.processor.InjectAnnotationProcessor</annotationProcessor>
<annotationProcessor>
co.aurasphere.revolver.annotation.processor.RevolverContextAnnotationProcessor</annotationProcessor>
</annotationProcessors>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
The problem is that when I try to build the project I get a CompilationFailureException because Maven can't find the processors.
I've found other questions like this, solved by putting the dependency outside the plugin. I tried that, but nothing changed for me.
Am I missing something?
Thank you.
EDIT
Here is my dependency on another project which contains both the processor and the annotations:
<dependencies>
<dependency>
<groupId>co.aurasphere</groupId>
<artifactId>revolver-annotation-processor</artifactId>
<version>0.0.3-SNAPSHOT</version>
</dependency>
</dependencies>
EDIT 2:
After further investigation, I decided to decompile the processor JAR (built with Maven) and it happens that... my classes are not there. For some reasons, Maven is not compiling my classes into the JAR and that's why the classes are not found. I've tried figuring out what's wrong on that build (this never happened to me before and I've used Maven for a while...).
First of all, the packaging on that project is jar.
The classes are all under src/main/java.
I've checked in my pom.xml that the classpath and source path is the same.
Here's the processor pom:
<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>
<groupId>co.aurasphere</groupId>
<artifactId>revolver-annotation-processor</artifactId>
<version>0.0.3-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!-- https://mvnrepository.com/artifact/javax.inject/javax.inject -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.velocity/velocity -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.7</version>
</dependency>
</dependencies>
EDIT 3
Here's the output of a maven clean install on the processor project. Unfortunately the output is too long and I had to post an external link even if I know it's not good.
EDIT 4
Here are some screenshots of my dependency hierarchy: and .
Since the project was originally created as an Eclipse simple Java project and then converted to a Maven one, I tried to create a new Maven project and move everything to the new one in the hope that the problem was the Eclipse plugin that messed something up, but the error was still there.
This is an extended version of the accepted answer above provided by #Aurasphere. Hopefully this will give some explanation to how the proposed solution works.
First, some background to what is happening here. Say, we want a custom annotation processor. We implement it and put it into a JAR as Maven artefact, so that it could be consumed by other projects. When such projects are being compiled, we want our annotation processor to be recognised by Java compiler and used appropriately. To make this happen, one needs to tell the compiler about a new custom processor. Compiler looks in the resources and checks FQN of classes listed in META-INF/services/javax.annotation.processing.Processor file. It tries to find these classes in classpath and load them to run the processing of annotations used upon classes that are currently being compiled.
So, we want our custom class to be mentioned in this file. We can ask a user of our library to put this file manually, but this is not intuitive and users could be frustrated why the promised processing of annotation doesn't work. That's why we might want to prepare this file in advance and deliver it together with the processor inside JAR of our Maven artefact.
The problem is that if we simply put this file with FQN of the custom processor in it, it will trigger compiler during compilation of our artefact, and since the processor itself is not yet compiled, the compiler will show the error about it. So we need to skip annotation processing to avoid this. This can be done using -proc:none, or with Maven:
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<proc>none</proc>
</configuration>
</plugin>
We might have unit tests that will need our annotation processor. In Maven, test compilation is carried out after main sources are built, and all classes are already available including our processor. We just need to add special step during processing of test sources which would use our annotation processor. This can be done using:
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>process-test-annotations</id>
<phase>generate-test-resources</phase>
<goals>
<goal>testCompile</goal>
</goals>
<configuration>
<proc>only</proc>
<annotationProcessors>
<annotationProcessor>fully.qualified.Name</annotationProcessor>
</annotationProcessors>
</configuration>
</execution>
</executions>
</plugin>
I've found the answer myself. I've figured out that the problem was the file javax.annotation.processing.Processor in META-INF/services/ with the configuration of the annotation processor's class. In order to fix the problem I had to add the following to the pom.xml configuration of my processor project:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<compilerArgument>
-proc:none
</compilerArgument>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
This let Maven build the classes into the actual jar and fixed the problem. I don't know if this is a bug or not but it surely looks strange to me. Thank you everybody for the help!
The easiest way is to register the annotation processor in the META-INF/services directory of the revolver-annotation-processor artifact. No Maven compiler configuration is needed.
Check if it's already registered, if not, register it yourself if you control the source code.
https://docs.oracle.com/javase/8/docs/api/java/util/ServiceLoader.html
If you control the source code I also recommend to package the processor in the same artifact as the annotations. Like this, whenever you're using one of the annotations, the annotation processor is also picked-up by the compiler.
The accepted answer here works by disabling all annotation processing, which may not be suitable if other annotation processors need to run during the compilation. Instead, the SPI configuration file listing the newly compiled annotation processor can be added in a post-processing step. I added a directory src/main/post-resources to my project and this plugin configuration:
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>
<id>annotation-processor-spi</id>
<phase>process-classes</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.outputDirectory}</outputDirectory>
<resources>
<resource>
<directory>src/main/post-resources</directory>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>

How can i get STS to resolve thy path to the web.xml i defined in a maven profile?

I have a maven project that has different environments for development and production. There are some parts in the web.xml that need to be removed for production. Until today, there was a antrunner based xml task that did exactly that. Now i want to remove the scripting-part and introduce 2 versions of the web.xml. Basically, i would extend the path "WEB-INF/web.xml" to "WEB-INF/dev/web.xml". This was configured in both profiles:
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<webxml.path>${project.basedir}/src/main/webapp/WEB-INF/dev/WEB.xml</webxml.path>
</properties>
</profile>
Same for the other profile, just with a different path.
Later, I will use the maven-war-plugin to make sure maven finds the file:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>default-war</id>
<phase>package</phase>
<goals>
<goal>war</goal>
</goals>
<configuration>
<warSourceDirectory>${project.build.directory}/${project.build.finalName}</warSourceDirectory>
<webXml>${webxml.path}</webXml>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
</archive>
</configuration>
</execution>
</executions>
</plugin>
And everything works fine, but just as long as I build from the commandline.
I told the Spring Tool Suite 3.7 to update with the dev profile,sadly it somehow refuses to resolve that path.
When I use the "create Descriptor-Stub" from the context menu, it even creates a file called ${webxml.path} with default web.xml content.
The provided error message is:
web.xml is missing and failOnMissingWebXml is set to true
I dont want to disable that check (failOnMissingWebXml) if possible.
Is there any way to get STS to be a bit more eager on resolving variables?
Update:
While writing this, I found out, that it is possible to use the maven-resources plugin to copy the file manually to the respective path when building from the IDE. It would be great to get m2e to respect the attribute from the war-plugin. Or is this simply not possible? Is the buildprocess not executed by maven itself, even though i explicitly specified the external version?

Maven: how to do runable jar (uberjar) with included external libraries

Until now i made runnable jars with Ant and there were no problems with it.
However i now try to mavenize my project and i realy can't figured out how to do runable jar with this tool.
I've read tons of tutorials (also here, on Stackoverflow), helps, advices and... nothing. In my case all of them don't work which probably means i don't understand some basics.
I have such simple project:
This is app, witch use mysql-connector-java-5.1.24-bin.jar (placed in 'lib' dir) to connect to MySQL database.
I want to include this jar into final jar (DBPreformatter.jar).
I used assembly and shaded plugins in many configurations, but they NEVER added this jar into DBPreformatter.jar.
This is my pom.xml:
<modelVersion>4.0.0</modelVersion>
<groupId>com.icd4you</groupId>
<artifactId>DBPreformatter</artifactId>
<version>1.0.0</version>
<name>DBPreformatter</name>
<description>DB processing and cleaning tool</description>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>mysql-connector-java-5.1.24-bin</groupId>
<artifactId>mysql-connector-java-5.1.24-bin</artifactId>
<version>5.1.24</version>
<scope>system</scope>
<systemPath>${basedir}/lib/mysql-connector-java-5.1.24-bin.jar</systemPath>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<!-- WHAT SHOULD I USE HERE? -->
</plugins>
</build>
How to solve this problem?
There is a maven plugin Apache Maven Shade Plugin that will build an uber jar for you
Add the Maven Assembly plugin with the descriptor jar-with-dependencies:
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.pany.your.MainClass</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
Note that this doesn't add the JAR; instead it unpacks all JARs which are listed as dependencies and adds their content to the resulting JAR (so you'll see all the class files from the MySQL JAR in the result instead of the MySQL JAR itself).
EDIT There is a caveat, though: Maven ignores JARs with scope=system for many operations. See also: How to include external jars in maven jar build process?
If Maven doesn't add the JAR to the output, then you must install all JARs with this scope into your local maven repo ($HOME/.m2/repository) using the mvn install:file-install command. See http://maven.apache.org/plugins/maven-install-plugin/usage.html how to do that.
Note: Installing libraries in your local repo is the preferred way; you should really consider it. For one, the scope=system will no longer confuse you (since many plugins handle them in a special way). Plus you need to do this only once. Afterwards, you can use this library in many Maven projects.
Before installing, you should check http://search.maven.org/ to see if the dependency isn't already known to Maven.
MySQL is: http://search.maven.org/#artifactdetails%7Cmysql%7Cmysql-connector-java%7C5.1.32%7Cjar

NoClassDefFoundError on Maven dependency

My first use of Maven and I'm stuck with dependencies.
I created a Maven project with Eclipse and added dependencies, and it was working without problems.
But when I try to run it via command line:
$ mvn package # successfully completes
$ java -cp target/bil138_4-0.0.1-SNAPSHOT.jar tr.edu.hacettepe.cs.b21127113.bil138_4.App # NoClassDefFoundError for dependencies
It downloads dependencies, successfully builds, but when I try to run it, I get NoClassDefFoundError:
Exception in thread "main" java.lang.NoClassDefFoundError: org/codehaus/jackson/JsonParseException
at tr.edu.hacettepe.cs.b21127113.bil138_4.db.DatabaseManager.<init>(DatabaseManager.java:16)
at tr.edu.hacettepe.cs.b21127113.bil138_4.db.DatabaseManager.<init>(DatabaseManager.java:22)
at tr.edu.hacettepe.cs.b21127113.bil138_4.App.main(App.java:10)
Caused by: java.lang.ClassNotFoundException: org.codehaus.jackson.JsonParseException
at java.net.URLClassLoader$1.run(URLClassLoader.java:217)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
at java.lang.ClassLoader.loadClass(ClassLoader.java:321)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
... 3 more
My pom.xml is like this:
<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>
<groupId>tr.edu.hacettepe.cs.b21127113</groupId>
<artifactId>bil138_4</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>bil138_4</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>1.9.6</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.6</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
Can anyone help me?
By default, Maven doesn't bundle dependencies in the JAR file it builds, and you're not providing them on the classpath when you're trying to execute your JAR file at the command-line. This is why the Java VM can't find the library class files when trying to execute your code.
You could manually specify the libraries on the classpath with the -cp parameter, but that quickly becomes tiresome.
A better solution is to "shade" the library code into your output JAR file. There is a Maven plugin called the maven-shade-plugin to do this. You need to register it in your POM, and it will automatically build an "uber-JAR" containing your classes and the classes for your library code too when you run mvn package.
To simply bundle all required libraries, add the following to your POM:
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.4.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
...
</project>
Once this is done, you can rerun the commands you used above:
$ mvn package
$ java -cp target/bil138_4-0.0.1-SNAPSHOT.jar tr.edu.hacettepe.cs.b21127113.bil138_4.App
If you want to do further configuration of the shade plugin in terms of what JARs should be included, specifying a Main-Class for an executable JAR file, and so on, see the "Examples" section on the maven-shade-plugin site.
when I try to run it, I get NoClassDefFoundError
Run it how? You're probably trying to run it with eclipse without having correctly imported your maven classpath. See the m2eclipse plugin for integrating maven with eclipse for that.
To verify that your maven config is correct, you could run your app with the exec plugin using:
mvn exec:java -D exec.mainClass=<your main class>
Update: First, regarding your error when running exec:java, your main class is tr.edu.hacettepe.cs.b21127113.bil138_4.App. When talking about class names, they're (almost) always dot-separated. The simple class name is just the last part: App in your case. The fully-qualified name is the full package plus the simple class name, and that's what you give to maven or java when you want to run something. What you were trying to use was a file system path to a source file. That's an entirely different beast. A class name generally translates directly to a class file that's found in the class path, as compared to a source file in the file system. In your specific case, the class file in question would probably be at target/classes/tr/edu/hacettepe/cs/b21127113/bil138_4/App.class because maven compiles to target/classes, and java traditionally creates a directory for each level of packaging.
Your original problem is simply that you haven't put the Jackson jars on your class path. When you run a java program from the command line, you have to set the class path to let it know where it can load classes from. You've added your own jar, but not the other required ones. Your comment makes me think you don't understand how to manually build a class path. In short, the class path can have two things: directories containing class files and jars containing class files. Directories containing jars won't work. For more details on building a class path, see "Setting the class path" and the java and javac tool documentation.
Your class path would need to be at least, and without the line feeds:
target/bil138_4-0.0.1-SNAPSHOT.jar:
/home/utdemir/.m2/repository/org/codehaus/jackson/jackson-core-asl/1.9.6/jackson-core-asl-1.9.6.jar:
/home/utdemir/.m2/repository/org/codehaus/jackson/jackson-mapper-asl/1.9.6/jackson-mapper-asl-1.9.6.jar
Note that the separator on Windows is a semicolon (;).
I apologize for not noticing it sooner. The problem was sitting there in your original post, but I missed it.
You have to make classpath in pom file for your dependency. Therefore you have to copy all the dependencies into one place.
Check my blog.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>$fullqualified path to your main Class</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
This is due to Morphia jar not being part of your output war/jar. Eclipse or local build includes them as part of classpath, but remote builds or auto/scheduled build don't consider them part of classpath.
You can include dependent jars using plugin.
Add below snippet into your pom's plugins section
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
For some reason, the lib is present while compiling, but missing while running.
My situation is, two versions of one lib conflict.
For example, A depends on B and C, while B depends on D:1.0, C depends on D:1.1, maven may
just import D:1.0. If A uses one class which is in D:1.1 but not in D:1.0, a NoClassDefFoundError will be throwed.
If you are in this situation too, you need to resolve the dependency conflict.
I was able to work around it by running mvn install:install-file with -Dpackaging=class. Then adding entry to POM as described here:
Choosing to Project -> Clean should resolve this

Categories