Question

I need some help with trying to get an executable working. This is a tricky one and I've narrowed it down to the fact that something is different with the way that maven exec runs things and how either the maven shade plugin or the maven assembly plugin is packaging the files.

I'm building a REST service in Java with Netty and JAX-RS and use Jackson to translate from POJOs to JSON.

The server starts up correctly when executing either mvn exec:java or java -jar. But when making a request against the java -jar file, I get the following error:

Could not find MessageBodyWriter for response object of type: [Ljava.lang.Object; of media type: application/json

It seems like something isn't being packaged correctly, but I'm not sure what. Transitive dependencies are missing, maybe?

Here's my POM:

<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>

<groupId>com.test.myserver</groupId>
<artifactId>myserver</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>

<name>myserver</name>
<url>http://maven.apache.org</url>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<repositories>
    <repository>
        <id>oss-sonatype</id>
        <name>oss-sonatype</name>
        <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
    </repository>
</repositories>

<build>
    <plugins>
        <!-- For executing in maven itself (mvn exec:java) -->
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>exec-maven-plugin</artifactId>
            <version>1.2.1</version>
            <executions>
                <execution>
                    <goals>
                        <goal>java</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <mainClass>com.test.myserver.App</mainClass>
            </configuration>
        </plugin>
        <plugin>
            <!-- for packaging (mvn package) -->
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>2.2</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <transformers>
                            <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                <mainClass>com.test.myserver.App</mainClass>
                            </transformer>
                        </transformers>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <!-- The configuration of maven-assembly-plugin -->
        <plugin>
            <!-- for packaging (mvn compile assembly:single) -->
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.4</version>
            <!-- The configuration of the plugin -->
            <configuration>
                <archive>
                    <manifest>
                        <mainClass>com.test.myserver.App</mainClass>
                    </manifest>
                </archive>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
        </plugin>
    </plugins>
</build>

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>LATEST</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.googlecode.plist</groupId>
        <artifactId>dd-plist</artifactId>
        <version>LATEST</version>
    </dependency>

    <!-- MongoDB -->
    <dependency>
        <groupId>org.mongodb</groupId>
        <artifactId>mongo-java-driver</artifactId>
        <version>2.12.0</version>
    </dependency>
    <dependency>
        <groupId>org.mongojack</groupId>
        <artifactId>mongojack</artifactId>
        <version>2.1.0-SNAPSHOT</version>
    </dependency>

    <!-- REST Server -->
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jaxrs</artifactId>
        <version>LATEST</version>
    </dependency>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-netty</artifactId>
        <version>LATEST</version>
    </dependency>
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jackson2-provider</artifactId>
        <version>LATEST</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>LATEST</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-simple</artifactId>
        <version>LATEST</version>
    </dependency>
    <dependency>
        <groupId>org.reflections</groupId>
        <artifactId>reflections</artifactId>
        <version>LATEST</version>
    </dependency>
</dependencies>

Maven shade is executed with mvn package. Maven assembly is executed with mvn compile assembly:single.

Thanks in advance!

EDIT

I checked mvn dependency:tree against the output for mvn shade and for all intents, they look the same.

Output from dependency tree

$ mvn dependency:tree
[INFO] Scanning for projects...
[INFO]
[INFO] Using the builder org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder with a thread count of 1
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building myserver 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ myserver ---
[INFO] com.test.myserver:myserver:jar:1.0-SNAPSHOT
[INFO] +- junit:junit:jar:4.11:test
[INFO] |  \- org.hamcrest:hamcrest-core:jar:1.3:test
[INFO] +- com.googlecode.plist:dd-plist:jar:1.8:compile
[INFO] +- org.mongodb:mongo-java-driver:jar:2.12.0:compile
[INFO] +- org.mongojack:mongojack:jar:2.1.0-SNAPSHOT:compile
[INFO] |  +- com.fasterxml.jackson.core:jackson-databind:jar:2.2.3:compile
[INFO] |  +- de.undercouch:bson4jackson:jar:2.2.0:compile
[INFO] |  +- javax.persistence:persistence-api:jar:1.0.2:compile
[INFO] |  \- commons-io:commons-io:jar:2.4:compile
[INFO] +- org.jboss.resteasy:resteasy-jaxrs:jar:3.0.8.Final:compile
[INFO] |  +- org.jboss.resteasy:jaxrs-api:jar:3.0.8.Final:compile
[INFO] |  +- org.jboss.spec.javax.annotation:jboss-annotations-api_1.1_spec:jar:1.0.1.Final:compile
[INFO] |  +- javax.activation:activation:jar:1.1:compile
[INFO] |  +- org.apache.httpcomponents:httpclient:jar:4.2.1:compile
[INFO] |  |  +- org.apache.httpcomponents:httpcore:jar:4.2.1:compile
[INFO] |  |  +- commons-logging:commons-logging:jar:1.1.1:compile
[INFO] |  |  \- commons-codec:commons-codec:jar:1.6:compile
[INFO] |  \- net.jcip:jcip-annotations:jar:1.0:compile
[INFO] +- org.jboss.resteasy:resteasy-netty:jar:3.0.8.Final:compile
[INFO] |  \- io.netty:netty:jar:3.6.4.Final:compile
[INFO] +- org.jboss.resteasy:resteasy-jackson2-provider:jar:3.0.8.Final:compile
[INFO] |  +- com.fasterxml.jackson.core:jackson-core:jar:2.3.2:compile
[INFO] |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.3.2:compile
[INFO] |  \- com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:jar:2.3.2:compile
[INFO] |     +- com.fasterxml.jackson.jaxrs:jackson-jaxrs-base:jar:2.3.2:compile
[INFO] |     \- com.fasterxml.jackson.module:jackson-module-jaxb-annotations:jar:2.3.2:compile
[INFO] +- org.slf4j:slf4j-api:jar:1.7.7:compile
[INFO] +- org.slf4j:slf4j-simple:jar:1.7.7:compile
[INFO] \- org.reflections:reflections:jar:0.9.9-RC1:compile
[INFO]    +- com.google.guava:guava:jar:11.0.2:compile
[INFO]    |  \- com.google.code.findbugs:jsr305:jar:1.3.9:compile
[INFO]    +- org.javassist:javassist:jar:3.16.1-GA:compile
[INFO]    \- dom4j:dom4j:jar:1.6.1:compile
[INFO]       \- xml-apis:xml-apis:jar:1.0.b2:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.999 s
[INFO] Finished at: 2014-04-22T17:09:47-08:00
[INFO] Final Memory: 13M/310M
[INFO] ------------------------------------------------------------------------

Output from shade

$ mvn package
[INFO]
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ myserver ---
[INFO] Building jar: /myserver/target/myserver-1.0-SNAPSHOT.jar
[INFO]
[INFO] --- maven-shade-plugin:2.2:shade (default) @ myserver ---
[INFO] Including com.googlecode.plist:dd-plist:jar:1.8 in the shaded jar.
[INFO] Including org.mongodb:mongo-java-driver:jar:2.12.0 in the shaded jar.
[INFO] Including org.mongojack:mongojack:jar:2.1.0-SNAPSHOT in the shaded jar.
[INFO] Including com.fasterxml.jackson.core:jackson-databind:jar:2.2.3 in the shaded jar.
[INFO] Including de.undercouch:bson4jackson:jar:2.2.0 in the shaded jar.
[INFO] Including javax.persistence:persistence-api:jar:1.0.2 in the shaded jar.
[INFO] Including commons-io:commons-io:jar:2.4 in the shaded jar.
[INFO] Including org.jboss.resteasy:resteasy-jaxrs:jar:3.0.8.Final in the shaded jar.
[INFO] Including org.jboss.resteasy:jaxrs-api:jar:3.0.8.Final in the shaded jar.
[INFO] Including org.jboss.spec.javax.annotation:jboss-annotations-api_1.1_spec:jar:1.0.1.Final in the shaded jar.
[INFO] Including javax.activation:activation:jar:1.1 in the shaded jar.
[INFO] Including org.apache.httpcomponents:httpclient:jar:4.2.1 in the shaded jar.
[INFO] Including org.apache.httpcomponents:httpcore:jar:4.2.1 in the shaded jar.
[INFO] Including commons-logging:commons-logging:jar:1.1.1 in the shaded jar.
[INFO] Including commons-codec:commons-codec:jar:1.6 in the shaded jar.
[INFO] Including net.jcip:jcip-annotations:jar:1.0 in the shaded jar.
[INFO] Including org.jboss.resteasy:resteasy-netty:jar:3.0.8.Final in the shaded jar.
[INFO] Including io.netty:netty:jar:3.6.4.Final in the shaded jar.
[INFO] Including org.jboss.resteasy:resteasy-jackson2-provider:jar:3.0.8.Final in the shaded jar.
[INFO] Including com.fasterxml.jackson.core:jackson-core:jar:2.3.2 in the shaded jar.
[INFO] Including com.fasterxml.jackson.core:jackson-annotations:jar:2.3.2 in the shaded jar.
[INFO] Including com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:jar:2.3.2 in the shaded jar.
[INFO] Including com.fasterxml.jackson.jaxrs:jackson-jaxrs-base:jar:2.3.2 in the shaded jar.
[INFO] Including com.fasterxml.jackson.module:jackson-module-jaxb-annotations:jar:2.3.2 in the shaded jar.
[INFO] Including org.slf4j:slf4j-api:jar:1.7.7 in the shaded jar.
[INFO] Including org.slf4j:slf4j-simple:jar:1.7.7 in the shaded jar.
[INFO] Including org.reflections:reflections:jar:0.9.9-RC1 in the shaded jar.
[INFO] Including com.google.guava:guava:jar:11.0.2 in the shaded jar.
[INFO] Including com.google.code.findbugs:jsr305:jar:1.3.9 in the shaded jar.
[INFO] Including org.javassist:javassist:jar:3.16.1-GA in the shaded jar.
[INFO] Including dom4j:dom4j:jar:1.6.1 in the shaded jar.
[INFO] Including xml-apis:xml-apis:jar:1.0.b2 in the shaded jar.
[INFO] Replacing original artifact with shaded artifact.
[INFO] Replacing /myserver/target/myserver-1.0-SNAPSHOT.jar with /myserver/target/myserver-1.0-SNAPSHOT-shaded.jar
[INFO] Dependency-reduced POM written at: /myserver/dependency-reduced-pom.xml
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.658 s
[INFO] Finished at: 2014-04-22T17:05:50-08:00
[INFO] Final Memory: 39M/310M
[INFO] ------------------------------------------------------------------------
Was it helpful?

Solution

The shade plugin configuration is missing the service transformer which merges the META-INF/services files used by the service discovery mechanism.

Here is an example:

<transformers>
    <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
        <mainClass>com.example.helloworld.HelloWorldApplication</mainClass>
    </transformer>
</transformers>

OTHER TIPS

It's interesting because I asked myself the question yesterday, "why do I need an über jar?" And, as it turns out, I don't and probably shouldn't be using an über jar. Alexey correctly answered the question to solve the immediate problem, but I also wanted to post an alternate solution that I figured out for doing things a little bit differently.

Rather than using the shade plugin to build an über jar, I decided to create a standard jar and export all the dependencies needed to run my application. This means that I now use the Maven Jar Plugin to create my jar and the Maven Dependency Plugin to export the libraries. Here's what the build section of the pom.xml looks like:

<build>
    <plugins>
        <!-- For copying the libraries to the output directory -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <version>2.8</version>
            <executions>
                <execution>
                    <id>copy-dependencies</id>
                    <phase>package</phase>
                    <goals>
                        <goal>copy-dependencies</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>${project.build.directory}/lib</outputDirectory>
                        <overWriteReleases>false</overWriteReleases>
                        <overWriteSnapshots>false</overWriteSnapshots>
                        <overWriteIfNewer>true</overWriteIfNewer>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <!-- Create the executable jar -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.4</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <classpathPrefix>lib/</classpathPrefix>
                        <mainClass>com.test.myserver.App</mainClass>
                        <useUniqueVersions>false</useUniqueVersions>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
    </plugins>
</build>

Since my output directory is target/, my jar is generated as target/myserver-1.0-SNAPSHOT.jar and all the dependencies are in target/lib/. The maven-jar-plugin also build the classpath and points them correctly to the lib/ directory, so I'm pretty much set. This also makes it easier in the future to replace individual libraries as they are updated, rather than uploading an entirely new jar.

Building the jar and copying the dependencies is simply mvn install from the command line.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top