Turns out, the root of my problem was a conflict with the javax.ws.rs.ext.Providers file that occurs when the maven assembly plugin creates the jar. (This file can be found in the uberjar within META-INF -> services -> javax.ws.rs.ext.Providers)
The Providers file contains a list of available provider classes. Within the dependencies of my project this file exists in more than one place, and the different copies contain different provider lists. The maven assembly plugin simply chooses one version to include in the jar, and so at runtime the required "writer" class cannot be found: This class is not listed in the Providers file within the jar.
I used the maven shade plugin to overcome this problem. The shade plugin contains a facility to selectively merge duplicate files contained within the dependency tree. Within pom.xml:
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/services/javax.ws.rs.ext.Providers</resource>
</transformer>
Tells maven to merge by appending any duplicates of javax.ws.rs.ext.Providers.
Also, by setting the maven shade plugin to execute during the package
phase of my build, and then the maven assembly plugin to execute at the install
phase, I was able to create an executable uberjar, then package that uberjar within a .zip file, all with a simple mvn clean install
invocation.
Here's what my pom.xml looks like:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
...
</parent>
<groupId>com.foo.bar</groupId>
<artifactId>my-app</artifactId>
<packaging>jar</packaging>
<version>2.1.0.0-SNAPSHOT</version>
<name>My App</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<issues-product>MyApp</issues-product>
<issues-component>MY-APP</issues-component>
</properties>
<dependencies>
...
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.foo.bar.MyMainClass</mainClass>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/services/javax.ws.rs.ext.Providers</resource>
</transformer>
</transformers>
<filters>
<filter>
<artifact>*:*</artifact>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2.2</version>
<configuration>
<finalName>${project.artifactId}</finalName>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>src/assembly/my-app-assembly.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</project>
And here is my-app-assembly.xml:
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/2.2.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/2.2.2 http://maven.apache.org/xsd/assembly-2.2.2.xsd">
<id>bin</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.basedir}</directory>
<outputDirectory/>
<includes>
<include>Readme.pdf</include>
<include>config\</include>
<include>input\</include>
<include>output\</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.build.directory}</directory>
<outputDirectory>bin\java\</outputDirectory>
<includes>
<include>my-app.jar</include>
</includes>
</fileSet>
</fileSets>
</assembly>