Monday 29 September 2008

Maven2 assembly plugin and jar signing

We use a java applet to talk to the local print service, which means to distribute it we need to sign the jar file. Normally, in Maven2 you'd set the following in your pom.xml:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-jar-plugin</artifactId>
  <executions>
    <execution>
      <phase>package</phase>
      <goals>
        <goal>sign
      </goals>
    </execution>
  </executions>
  <configuration>
    <keystore>src/main/resources/code-cert.pfx</keystore>
    <type>pkcs12</type>
    <alias>SomeAlias</alias>
    <storepass>SomePassword</storepass>
    <signedjar>${project.build.directory}/signed/${project.build.finalName}.jar</signedjar>
    <verify>true</verify>
  </configuration>
</plugin>
]]>

and when you run

$ mvn clean package

all is well and good.  However, when you come to want to include resources in your jar, by using the following plugin:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-assembly-plugin</artifactId>
  <configuration>
    <descriptorRefs>
      <descriptorRef>jar-with-dependencies</descriptorRef>
    </descriptorRefs>
    <excludes>
      <exclude>**/com/spektrix/**</exclude>
    </excludes>
  </configuration>
  <executions>
    <execution>
      <id>make-assembly</id>
      <phase>package</phase>
      <goals>
        <goal>attached</goal>
      </goals>
    </execution>
  </executions>
</plugin>      

You'll need to add some configuration to the original element.

Firstly, you'll need a jarPath element:

<configuration>
  ...
  <jarPath>${project.build.directory}/${project.build.FinalName}-${project.packaging}-with-dependencies.${project.packaging}</jarPath>
  ...
</configuration>


To tell it to sign the full jar, rather than the basic one.  However, this is still not quite right, and you'll get the following error:

[INFO] jarsigner: unable to sign jar: java.util.zip.ZipException: duplicate entry: some/path/to/a/Class.class

If we look at the contents of the full jar, you'll see the contents of your project added twice!  To get around this you'll need the following in your configuration section:

<configuration>
  <excludes>
    <exclude>**/com/company/**<exclude>
  </excludes>
  ...
</configuration>

With one line for each such error you get from the jarsigner.  Eventually, all your project contents will only be added once and you'll see:

[INFO] [jar:sign {execution: default}]
[debug] jarsigner executable=[C:\Program Files\Java\jdk1.6.0_10\jre\..\bin\jarsi
gner.exe]
[debug] Executing: cmd.exe /X /C '""C:\Program Files\Java\jdk1.6.0_10\jre\..\bin
\jarsigner.exe" -verify <Some Jar File>"'
[info] jar verified.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------

4 comments:

Unknown said...

When you say you need to add a few configuration elements to the "initial configuration", which configuration are you talking about? The maven-assembly-plugin one or the other one?

AgentIcarus said...

Yes, I think I meant the assembly-plugin configuration

Unknown said...

It seems this (duplicate entry in jar) is of course assembly plugin bug.

This should be corrected in version 2.2-beta3.

maven-assembly-plugin
2.2-beta-5
Working for me.

Unknown said...

Now you can use the jarsigner-plugin for this requirement. All jars are signed http://maven.apache.org/plugins/maven-jarsigner-plugin/