Maven: How do I get .so libraries bundled in package - java

I have a third party library coming with .jar and .so file.
I configured pom.xml as following:
<dependency>
<groupId>com.abc.def</groupId>
<artifactId>sdc</artifactId>
<version>1.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.abc.def</groupId>
<artifactId>sdc</artifactId>
<version>3</version>
<scope>compile</scope>
<type>so</type>
</dependency>
With this configure, I successfully tested through Intellij and apk file under target contains structure like lib/armeabi/sdc.so
However, after I do mvn clean package, the apk file generated did not contain sdc.so file, and after installing apk file on android device, lib folder is empty.
Searching through the internet, and did not find answer.
Btw, I do add <nativeLibrariesDirectory>${project.basedir}/libs</nativeLibrariesDirectory> into pluginManagement as mentioned Native libraries (.so files) are not added to an android project, but does not help.
Updates:
If someone is facing same problem as I am that SO file did not copy over, please try manually copy the so file over as following:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<id>copy</id>
<phase>prepare-package</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>com.abc.def</groupId>
<artifactId>libdef</artifactId>
<version>2.1.3</version>
<type>so</type>
<destFileName>libdef.so</destFileName>
</artifactItem>
</artifactItems>
<outputDirectory>${project.build.directory}/libs/armeabi</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

I suggest you to use maven-android-plugin version 2.8.3 or more.
The scope of your native lib must be runtime (not sure it is required, but anyway it's a fact)
The artifactId must start with lib (i.e. it must be libsdc)
<dependency>
<groupId>com.abc.def</groupId>
<artifactId>libsdc</artifactId>
<version>3</version>
<scope>runtime</scope>
<type>so</type>
</dependency>
The artifactId will be the library name so load it with this line of code
System.loadLibrary("sdc");
reference
Note: I don't know if sdc if the real artifactId, but if it's the case you must consider re-publishing it with the lib prefix.

I would suggest looking into the Assembly plugin: http://maven.apache.org/plugins/maven-assembly-plugin/ I have not used it in any Android project yet, but I do use it in my regular java server projects which require non-maven items be in expected locations.

Related

neo4j procedure depending on signed jar (mapdb)

I have created a neo4j user-defined procedure. It also compiles and works in neo4j.
Recently though, I added a dependency to my procedure plugin that prevents neo4j from starting when I try to run the newly built jar. Concretely, I receive following exception at the bottom of the stack trace:
Caused by: java.lang.SecurityException: Invalid signature file digest for Manifest main attributes
The only thing I changed is to add MapDB to my dependencies. So I suspect that it depends on some signed artifact. As it turns out neo4j plugins are "uber-jars" (i.e., shaded jars) which doesn't work very well with signed dependencies.
I figured I could try to exclude MapDB from the shading by changing the scope to provided and additionally adding the mapdb jar to plugins folder of neo4j. So the plugins folder of neo4j now includes both mapdb.jar and myprocedure.jar.
This doesn't seem to work though: neo4j starts, but when calling my procedure I receive a ClassNotFound Exception.
Any ideas on how I can solve this dilemma? I really depend on something like MapDB as my graph is very large and keeping everything in my procedure in-memory regularly leads to memory exceptions.
Many thanks in advance!
The important part of my pom.xml should it help (I started off with the procedure template so it still looks quite similar):
<dependencies>
<!-- other dependencies that don't make a difference ... -->
<dependency>
<groupId>org.mapdb</groupId>
<artifactId>mapdb</artifactId>
<version>3.0.7</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j</artifactId>
<version>${neo4j.version}</version>
<scope>provided</scope>
</dependency>
<!-- Test Dependencies -->
<dependency>
<groupId>org.neo4j.test</groupId>
<artifactId>neo4j-harness</artifactId>
<version>${neo4j.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.neo4j.driver</groupId>
<artifactId>neo4j-java-driver</artifactId>
<version>1.4.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<!-- Neo4j Procedures require Java 8 -->
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<!-- This generates a jar-file with our procedure code,
plus any dependencies marked as `compile` scope.
This should then be deployed in the `plugins` directory
of each Neo4j instance in your deployment.
After a restart, the procedure is available for calling. -->
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
So, one solution that worked was to use the maven-assembly-plugin instead of the maven-shade-plugin. The assembly plugin creates a standalone jar with all dependencies without re-packaging all dependencies.
Of course, I had to remove the <scope>provided</scope> for mapdb so it is also included in the assembled jar.
The rest is just replacing the shade plugin with following snippet (thanks to this question here):
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
Afterwards I received another exception which I thought was due to a wrong signature:
Caused by: java.lang.VerifyError ...
Turns out this was just because I had another procedure in neo4j that uses the same dependencies as mapdb. Quick fix was to remove that procedure library.
Of course, there are also other solutions, including removing the signature, or re-signing it. However, I explicitly did not want to remove any signatures.
I'm not aware that neo4j is checking any jar signatures by default. I suspect the repackaging of mapdb artifact being the culprit.
To validate that, remove the shade or assembly plugin in and build a jar that solely contains your code. Copy that jar and the mapdb.jar into the plugin folder and observe logs during a restart.

How to use dependencies from a jar file?

I am trying to import a jar file and to use its dependencies into a Maven project.
The jar file I want to import is itself another Maven project and includes all of the dependencies of it.
I managed to import my jar file and to use the java code (from my packages in src/main in the Maven project jar file) but the project where I imported mt jar file still does not recognize the dependencies of the jar.
For example, I am trying to import org.json.JSONObject (whom dependency is defined in the jar file) but there is a compiling error.
Is there any way to do what I want or any other solution ?
Thank you !
(Sorry for the bad level of explanation, I am French and it is quite hard form me to explain in details my problem)
EDIT
Here are samples of my pom from my jar file :
<!-- One of the dependency I want to use -->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20160212</version>
<scope>test</scope>
</dependency>
<!-- The plugin I used to create my jar file with dependencies -->
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2</version>
<configuration>
<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>
I then included the jar file using an "in-project" repository as explained here : http://charlie.cu.cc/2012/06/how-add-external-libraries-maven/
The error message is a compiling error message saying that the org.json.JSONObject is not recognized :
package org.json does not exist
You add the json lib only for test scope.
Remove the scope and the error should gone.
<!-- One of the dependency I want to use -->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20160212</version>
</dependency>

GWT project deployment to tomcat in STS(Eclipse)

I have a maven project in STS(Eclipse) and I try deploying it to Tomcat 6 in STS. For maven install I use gwt-maven-plugin. Installed war contains all folders (WEB-INF/, META-INF/, compiled GWT frontend folder). When I deploy this project to tomcat (in STS), there are only WEB-INF and META-INF folders in webapps/project folder. Folder with compiled GWT frontend is nowhere to find. In context.xml I even tried to set docBase to installed war, but no difference in result. Have anyone an idea where problem could be?, because now I have to manually copy this folder to unpacked folder in webapps. Thanks alot.
Might be a configuration problem, post your gwt-maven-plugin xml here.
Here's mine, just for reference
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>${gwt.version}</version>
<configuration>
<logLevel>DEBUG</logLevel>
<style>PRETTY</style>
<runTarget>/ApplicationScaffold.html</runTarget>
<hostedWebapp>${project.build.directory}/${project.build.finalName}</hostedWebapp>
<!-- <modules><module>${project.groupId}.Main</module></modules>-->
<copyWebapp>true</copyWebapp>
<debugPort>8001</debugPort>
<extraJvmArgs>-Xmx900m</extraJvmArgs>
<!-- instruct plugin not to require open browser in test mode -->
<mode>htmlunit</mode>
<!-- compiler speed up -->
<draftCompile>true</draftCompile>
<optimizationLevel>0</optimizationLevel>
<disableAggressiveOptimization>true</disableAggressiveOptimization>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test</goal>
</goals>
</execution>
</executions>
<dependencies>
<!-- must override the plugin's default dependencies -->
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-user</artifactId>
<version>${gwt.version}</version>
</dependency>
<dependency>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-dev</artifactId>
<version>${gwt.version}</version>
</dependency>
</dependencies>
</plugin>

Proguard with Maven

I am trying to use Proguard to shrink the jar size.
I configured Proguard in Maven pom.xml. It failed to find all the embedded dependency jars.
It can read and parse out all dependency jars which is referenced in the current module, but for dependencies which are embedded in the other modules, it failed to find it.
For example, My current module is moduleA and it depends another module moduleB. And module B has a dependency moduleC. It can find all classes which are directly inside moduleB, but it failed to parse out all classes which are inside moduleC. My configuration for proguard is as following:
<plugin>
<!--groupId>com.pyx4me</groupId-->
<groupId>com.github.wvengen</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<executions>
<execution>
<id>proguard</id>
<phase>package</phase>
<goals>
<goal>proguard</goal>
</goals>
</execution>
</executions>
<configuration>
<injar>MyInput-${project.version}.jar</injar>
<outjar>MyInput-Processed-${project.version}.jar</outjar>
<options>
<option>-keep public class * { *; }</option>
<option>-ignorewarnings</option>
</options>
<libs>
<!--lib>${java.bootstrap.classes}</lib>
<lib>${java.cryptographic.extension.classes}</lib>
<lib>${java.secure.socket.extension.classes}</lib-->
</libs>
</configuration>
<dependencies>
<dependency>
<groupId>net.sf.proguard</groupId>
<artifactId>proguard-base</artifactId>
<version>4.10</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</plugin>
I had similar problem, however it could find the references mentioned in the plugin's configuration dependencies section.
However, if I tried to use the proguard-base-4.10 the proguard-maven-plugin (with com.pyx4me groupId) still used the proguard-4.3.jar (you can see it in the maven output in the console); looks like the plugin is only working with a "proguard" artifact, not a "proguard-base".
So I configured the dependencies section to look like:
<dependency>
<groupId>net.sf.proguard</groupId>
<artifactId>proguard</artifactId>
<version>4.10</version>
<scope>runtime</scope>
</dependency>
but this one is not available in the central maven repo (the latest version is 4.4).
What I did was to download the proguard-4.10 manually from proguard download section and install the proguard.jar in the local maven repository under the version 4.10 - and now everything works fine.
There is a newer version of that plugin at: https://github.com/wvengen/proguard-maven-plugin

Maven assembly include problem

Context
We have this application, using about 60 coding projects.
We have several products that are realized using this same code base, so
we follow the maven best-practices : we assemble each product using an assembly project, using the assembly plugin.
We have an historical assembly using Ant, that need many improvements. In a first phase, I am trying to obtain the same result using a clean Maven assembly. Later on, I will improve that one.
Question
In my assembly, I want to have the same jar artifact in several versions. I want:
commons-beanutils-1.7.0.jar
commons-beanutils-1.8.0.jar
I list both in my assembly project dependencies in my pom, but only one shows (the 1.8.0).
How could I do it?
This is my pom.xml for the assembly project. Everything works if I specify only one or the other, except I don't get the other one obviously.
pom.xml:
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.8.0</version>
</dependency>
Maven doesn't want you to do this because the behaviour at runtime is indeterminate.
If you define multiple dependencies with the same groupId and artifactId, and different versions, Maven will resolve the conflict and give you one of them. You should really look at resolving the conflict so that only one version is required.
If you do have a good reason to do this, to avoid the problem you need to specify the dependencies as artifactItems in the dependency plugin. The following config will copy both versions of the jar to target/output, if the dependency plugin is executed before the assembly plugin, you will be able to include the downloaded jars in your assembly by specifying a fileSet pointing to the target/output directory:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy</id>
<phase>package</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.7.0</version>
<type>jar</type>
<overWrite>false</overWrite>
</artifactItem>
<artifactItem>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.8.0</version>
<type>jar</type>
<overWrite>false</overWrite>
</artifactItem>
</artifactItems>
<outputDirectory>${project.build.directory}/output</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>true</overWriteSnapshots>
</configuration>
</execution>
</executions>
</plugin>

Categories