Our production application stack has a fair amount of external service connections that require the use of certs for SSL security. We used to use a static reference (e.g. /config/certs or c:\config\certs for you Windows people) to locate the certificates, but this was always suboptimal as it made the application less portable. I finally got around to moving from the static reference and landing on Java jar introspection to find the file (using something similar to ClassName.getResource("/cert.pks");).
This conversion worked very well and everything seemed fine until the change got to our continuous integration (or CI) box. That machine, a Centos distribution, kept failing with the error Invalid keystore format when we tried to initialize the keystore in code. I spent hours trying to figure out the difference between my local machine (running OS X, which worked fine) and the CI box. I finally diff’d the cert file in src/main/resources and the resulting file in target/classes. I discovered that the two files were radically different.
Maven has a very cool feature that not only copies values from src/main/resources into target/classes and, ultimately, the resulting Jar file but also can substitute tokens in text files as part of the build (referred to as “filtering”). To enable this, all you have to do is add
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
to your pom.xml file and you’re off to the races. However, Maven will process every file in the src/main/resources directory as part of performing this substitution. This normally wouldn’t be an issue, but certificate files contain some raw text and Maven dutifully filters them just as it would any resource. This caused a serious issue with the character encoding as Maven was writing out a file with a completely different encoding scheme than the file was created with. Basically, Maven filtering was corrupting our certs.
To fix this, I created a subdirectory off of src/main/resources (I called it binary) and added a manual exclusion in the pom.xml file. The resulting XML looks as follows:
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<excludes>
<exclude>**/binary/*</exclude>
</excludes>
</resource>
<resource>
<directory>src/main/resources/binary</directory>
</resource>
</resources>
This worked perfectly. Hopefully, it helps some of you as well!
