Grizzly and Jersey standalone jar
Question
I am trying to package Grizzly with Jersey as a single jar using Maven shade plugin. But I always get the message No container provider supports the type class org.glassfish.grizzly.http.server.HttpHandler
The code works fine in Eclipse, but not in a packaged jar:
public class Main {
private static URI getBaseURI() {
return UriBuilder.fromUri("http://localhost/").port(9998).build();
}
public static final URI BASE_URI = getBaseURI();
protected static HttpServer startServer() throws IOException {
System.out.println("Starting grizzly...");
ResourceConfig rc = new PackagesResourceConfig("share.test");
rc.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
return GrizzlyServerFactory.createHttpServer(BASE_URI, rc);
}
public static void main(String[] args) throws IOException {
HttpServer httpServer = startServer();
System.in.read();
httpServer.stop();
}
}
Here is the complete exception
$ java -jar target/webServiceTest-0.0.1-SNAPSHOT.jar
Starting grizzly...
Mar 20, 2012 12:48:53 PM com.sun.jersey.api.core.PackagesResourceConfig init
INFO: Scanning for root resource and provider classes in the packages:
share.test
Mar 20, 2012 12:48:54 PM com.sun.jersey.api.core.ScanningResourceConfig logClasses
INFO: Root resource classes found:
class share.test.NonJAXBBeanResource
class share.test.Hello
Mar 20, 2012 12:48:54 PM com.sun.jersey.api.core.ScanningResourceConfig init
INFO: No provider classes found.
Exception in thread "main" java.lang.IllegalArgumentException: No container provider supports the type class org.glassfish.grizzly.http.server.HttpHandler
at com.sun.jersey.api.container.ContainerFactory.createContainer(ContainerFactory.java:196)
at com.sun.jersey.api.container.ContainerFactory.createContainer(ContainerFactory.java:134)
at com.sun.jersey.api.container.grizzly2.GrizzlyServerFactory.createHttpServer(GrizzlyServerFactory.java:242)
at share.test.Main.startServer(Main.java:27)
at share.test.Main.main(Main.java:31)
I am building the jar package using maven with
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.5</version>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Main-Class>share.test.Main</Main-Class>
<Build-Number>1</Build-Number>
</manifestEntries>
</transformer>
</transformers>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Do I need to change the shade plugin to include anything else?
Solution
The error looks like the plugin is not merging the META-INF/services records from different jars correctly - if there are multiple files with the same name in META-INF/services directory of several jars, they need to be merged, not replaced one by the other. Check if that is the case.
OTHER TIPS
The following links helped me figuring out the solution below:
- http://maven.apache.org/guides/mini/guide-assemblies.html
- http://maven.apache.org/plugins/maven-assembly-plugin/descriptor-refs.html
- How can I merge resource files in a Maven assembly?
especially the answer
Instead of using the jar-with-dependencies as the descriptorRef of your assembly-plugin configuration you create our own e.g. in src/assembly/depmerge.xml (see below). This assembly configuration will add a containerDescriptorHandler that cares for the META-INF/services.
run
mvn clean compile assembly:single
to get a jar file in target which you can call with
java -jar target/x.y.-version-jar-with-dependencies.jar
pom.xml:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.3</version>
<configuration>
<archive>
<manifest>
<mainClass>${mainClass}</mainClass>
</manifest>
</archive>
<descriptor>src/assembly/depmerge.xml</descriptor>
</configuration>
</plugin>
src/assembly/depmerge.xml:
<!--
see http://maven.apache.org/guides/mini/guide-assemblies.html
see http://maven.apache.org/plugins/maven-assembly-plugin/descriptor-refs.html
-->
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<!-- TODO: a jarjar format would be better -->
<id>jar-with-dependencies-and-services</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<outputDirectory>/</outputDirectory>
<useProjectArtifact>true</useProjectArtifact>
<unpack>true</unpack>
<scope>runtime</scope>
</dependencySet>
</dependencySets>
<!--
https://stackoverflow.com/questions/1607220/how-can-i-merge-resource-files-in-a-maven-assembly
-->
<containerDescriptorHandlers>
<containerDescriptorHandler>
<handlerName>metaInf-services</handlerName>
</containerDescriptorHandler>
</containerDescriptorHandlers>
</assembly>
I just made the stupid mistake. Configure maven-assembly-plugin in pom as well.
Assembly seems to replace META-INF/services and override "com.sun.jersey.server.impl.container.grizzly2.GrizzlyContainerProvider " in File com.sun.jersey.spi.container.ContainerProvider
As guide http://maven.apache.org/plugins/maven-assembly-plugin/ mentioned, If your project wants to package your artifact in an uber-jar, the assembly plugin provides only basic support. For more control, use the Maven Shade Plugin.
<!-- mvn assembly:assembly -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>XXX.DaemonMain</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>