Maven assembly include problem - java

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>

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.

process-resource-bundles maven error calssnotfoundexception org.apache.commons.collections.ExtendedProperties

Trying to build an example from camel via mvn package
apache-camel-2.22.0/examples/camel-example-cdi-xml
Getting an error never seen before, i checked dependency tree for transitive deps and apache-collections is 3.2.1 and not corrupt so can't explain it, obviously i know what it means, just can't figure out why it's happening because everything that should be required is provided:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-remote-resources-plugin:1.5:process (process-resource-bundles) on project camel-example-cdi-xml: Execution process-resource-bundles of goal org.apache.maven.plugins:maven-remote-resources-plugin:1.5:process failed: A required class was missing while executing org.apache.maven.plugins:maven-remote-resources-plugin:1.5:process: org/apache/commons/collections/ExtendedProperties
Not really sure how to trouble shoot it.
I tried building with several different versions of maven. JDK = 1.8
update pom.xml add the following code
<plugin>
<artifactId>maven-remote-resources-plugin</artifactId>
<version>1.6.0</version>
<dependencies>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-lang/commons-lang -->
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
</dependencies>
<executions>
<execution>
<goals>
<goal>bundle</goal>
</goals>
</execution>
</executions>
</plugin>

Eclipse tycho updating version to svn revision

i want to update the minor version number of
product, all feature and all modules to its coresponding svn revision number (later only mentioned as buildNumber).
this shall work automatically, so no modification on .product, feature.xml, MANIFEST.MF nor pom.xml are needed
My RCP Applicatin has the following structure (names simplified)
parent
feature-core
feature-addons(4)
modules(loads)
product
i tried to include buildnumber-maven-plugin:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>create</goal>
</goals>
</execution>
</executions>
<configuration>
<doCheck>true</doCheck>
<doUpdate>true</doUpdate>
<providerImplementations>
<svn>javasvn</svn>
</providerImplementations>
</configuration>
<dependencies>
<dependency>
<groupId>com.google.code.maven-scm-provider-svnjava</groupId>
<artifactId>maven-scm-provider-svnjava</artifactId>
<!-- version>2.1.1</version -->
<!-- latest is 2.1.1 -->
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>org.tmatesoft.svnkit</groupId>
<artifactId>svnkit</artifactId>
<!-- version>1.8.11</version -->
<!-- latest is 1.8.11 -->
<version>1.7.8</version>
</dependency>
</dependencies>
</plugin>
and
<finalName>${project.artifactId}-${project.version}-r${buildNumber}</finalName>
but this only creates a zip file with the buildNumber and leaves the version untouched.
p2 update manager requires the version to change (a simple SNAPSHOT build does not work for my product)
so by now the version number is eg. 1.0.0 and should be automatically updated to 1.0.${buildNumber}
its ok, if this is not possible in the parent pom and needs to be done in each feature or modules pom
there is a feature in Tycho that updates the version qualifier (4th digit) to the timestamp of the latest git commit:
https://wiki.eclipse.org/Tycho/Reproducible_Version_Qualifiers
https://git.eclipse.org/c/tycho/org.eclipse.tycho.extras.git/tree/tycho-buildtimestamp-jgit/src/main/java/org/eclipse/tycho/extras/buildtimestamp/jgit/JGitBuildTimestampProvider.java
you would have to develop a similar BuildTimeStampProvider plexus component for SVN.

Maven won't exclude during copy-dependencies

I have a project that uses Netty 4.0.29 and I have another dependency that pulls in netty 3.9.0. I put in an exclusion but it is still roping in 3.9.0 when I run copy-dependencies.
<dependency>
<groupId>com.ning</groupId>
<artifactId>async-http-client</artifactId>
<version>1.9.31</version>
<exclusions>
<exclusion>
<groupId>io.netty</groupId>
<artifactId>netty</artifactId>
</exclusion>
</exclusions>
</dependency>
If I run mvn dependency:tree with this exclusion in place, I see that it is indeed excluded:
[INFO] +- com.ning:async-http-client:jar:1.9.31:compile
But when I run mvn clean dependency:copy-dependencies I see the jar 3.9.0 being copied along with the 4.0.29. According to the documentation and Google, this should not copy when there is an exclusion.
[INFO] Copying netty-3.9.0.Final.jar to /Users/udonom1/wk/141/coursecopy-api/target/dependency/netty-3.9.0.Final.jar
[INFO] Copying netty-all-4.0.29.Final.jar to /Users/udonom1/wk/141/coursecopy-api/target/dependency/netty-all-4.0.29.Final.jar
I tried excluding as suggested by the first answer below and that did not work.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>process-sources</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration> <outputDirectory>${project.build.directory}/lib</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
<excludeArtifactIds>io.netty:netty:3.9.0.Final</excludeArtifactIds>
</configuration>
</execution>
</executions>
</plugin>
I also added a dependency as further suggested:
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.0.29.Final</version>
</dependency>
What am I doing wrong?
For those who are having the same issue. I used mvn -X and discovered that dependency:tree is omitting two other jars that are referencing netty. I added exclusions for those and I'm good to go. Spent a whole day on this.
If you are writing not library you have simple way to control versions of any dependency in your project - dependencyManagement block in root pom file, example:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty</artifactId>
<version>4.0.29.Final</version>
</dependency>
</dependencies>
</dependencyManagement>
Additional bonuses from this block - you can omit version and scope for dependency in concrete dependency (with same group id, artifact id and packaging).
PS another look to your dependencies make me ask you: are you sure that this dependency have single maven artifact id? netty-all-4.0.29.Final.jar - seems that this artifact should have netty-all artifact id... If they have different artifact id's my recipe wouldn't help. In this case you should define build configuration for maven-dependency-plugin, example:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.10</version>
<configuration>
<excludeArtifactIds>io.netty:netty:3.9.0.Final</excludeArtifactIds>
</configuration>
</plugin>
</plugins>
</build>
or just use -DexcludeArtifactIds parameter in your maven call

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

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.

Categories