I am having problems building a maven project. I have a requirement to produce deterministic jar files, which must be binary-consistent across different builds and versions, in case there are no source code changes in between these builds. For the purpose, I have used this article for guidance.
I have successfully managed to build my jars and they are consistent up to my requirements. Here is my configuration:
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<id>step-1-remove-timestamp</id>
<phase>prepare-package</phase>
<configuration>
<target>
<touch datetime="01/01/2015 00:10:00 am">
<fileset dir="target/classes"/>
<fileset dir="src"/>
</touch>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
<execution>
<id>step-3-rename-assembly</id>
<phase>package</phase>
<configuration>
<target>
<copy file="${project.build.directory}/${project.build.finalName}-deterministic.zip"
tofile="${project.build.directory}/${project.build.finalName}.jar"/>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2.1</version>
<configuration>
<descriptors>
<descriptor>src/main/assembly/zip.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>step-2-make-assembly</id>
<phase>prepare-package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
In the above code I build and package the jar as a zip, then copy the zip over the expected jar artifact.
The problem with the above, is that maven still executes the maven-jar-plugin
, so the manually assembled jar is overwritten by the one of the maven-jar-plugin
. I do not want to use this jar, since it is not consistent with my requirements.
So, I have disabled the maven-jar-plugin
execution, by explicitly setting it to run for an invalid phase, like below: (saw that from other posts here)
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.5</version>
<executions>
<execution>
<id>default-jar</id>
<phase>never</phase>
<configuration>
<finalName>unwanted</finalName>
<classifier>unwanted</classifier>
</configuration>
</execution>
</executions>
</plugin>
Everything seems fine, until I discovered my main jar artifact is never installed in the .m2
directory. To correct this, I also added the maven-helper-plugin
so that I manually attach any artifacts I produce from the assembler plugin:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.9.1</version>
<executions>
<execution>
<id>attach-instrumented-jar</id>
<phase>verify</phase>
<goals>
<goal>attach-artifact</goal>
</goals>
<configuration>
<artifacts>
<artifact>
<file>${project.build.directory}/${project.build.finalName}.jar</file>
<type>jar</type>
</artifact>
</artifacts>
</configuration>
</execution>
</executions>
</plugin>
This leads to an error I am unable to solve:
[ERROR] Failed to execute goal org.codehaus.mojo:build-helper-maven-plugin:1.9.1:attach-artifact (attach-instrumented-jar) on project my-project: Execution attach-instrumented-jar of goal org.codehaus.mojo:build-helper-maven-plugin:1.9.1:attach-artifact failed: For artifact {full-name-of-my-project.jar}: An attached artifact must have a different ID than its corresponding main artifact. -> [Help 1]
Is there a way to overcome this issue? I've checked for solutions, and most recommend using classifiers, but I want to install the main artifact as would the maven-jar-plugin
. Other software we are developing will require the standard jar dependency, and we want to avoid complicating our setup by introducing classifiers unreasonably.
After some more trial and failures I happened to come with a working solution. I am posting it here with the hopes to either be useful, or to have any issues with pointed to me, as I am not really confident if this is a reliable approach.
So, the error I received
meant to me that I cannot manually install "again" the main artifact. Since that artifact is not produced anymore by the
maven-jar-plugin
, it never gets scheduled for installation even if the file is present (the antrun copy task produces a jar with the same name).Surprisingly, it needed a few little tricks to make this work again:
Re-enabled the
maven-jar-plugin
as it should be:This will produce the standard jar on the
package
phase, and most importantly, makes maven aware for it to be installed during theinstall
phase.Tweak the
maven-antrun-plugin
copy tasks to overwrite the already produced jar with the deterministic zip. The setup is nearly identical as in my question, so I am only adding the differences:The copy operation now has
overwrite="true"
specified. Originally, the copy operation seemed to ignore files in the destination if they already exist, and what happened is that themaven-jar-plugin
had already produced the default jar artifact when the copying occured. With this option set, themaven-antrun-plugin
now overrides the former jar with the deterministic one, and the latter becomes a subject of the maveninstall
phase.Removed the setup from the build-helper-maven-plugin, so that the main jar artifact is not copied a second time:
That's it, the correct jar is installed in the
.m2
dir.In case you don't have a plugin to create and attach main artifact for you, there is a more generic solution with Groovy Maven plugin:
Inspired by post https://stackoverflow.com/a/31513690/2053580 many thanks to https://stackoverflow.com/users/1314907/lukasz-guminski