Why does Play throw NoSuchMethodError for Netty's HttpRequest.headers() with Selendroid?

java, netty, playframework-2.0, selendroid

Solution

tl;dr Use `evicted` command, `exclude` and `force()` in the build with very helpful reports under `target/resolution-cache/reports/`. Don't forget about sbt-dependency-graph.

As said in Exclude specific transitive deps:

Sometimes it takes a bit of detective work to figure out which transitive deps to exclude.

I've experienced the very similar issue and the solution was to use proper dependency of Netty library (or rather exclude one to let `assembly` pass).

[microservice]> evicted
[info] Updating {file:/Users/jacek/work/.../}microservice...
[info] Resolving jline#jline;2.12 ...
[info] Done updating.
[warn] There may be incompatibilities among your library dependencies.
[warn] Here are some of the libraries that were evicted:
[warn]  * xml-apis:xml-apis:1.0.b2 -> 1.4.01 (caller: xerces:xercesImpl:2.11.0, dom4j:dom4j:1.6.1)
[warn]  * io.netty:netty:(3.6.6.Final, 3.6.3.Final) -> 3.9.3.Final (caller: com.typesafe.netty:netty-http-pipelining:1.1.2, com.typesafe.play:play_2.11:2.3.7, org.apache.cassandra:cassandra-all:2.0.8, com.netflix.astyanax:astyanax-cassandra:1.56.48)
[warn]  * joda-time:joda-time:1.6.2 -> 2.3 (caller: com.typesafe.play:play-json_2.11:2.3.7, com.netflix.astyanax:astyanax-core:1.56.48, com.typesafe.play:play_2.11:2.3.7, com.netflix.astyanax:astyanax-cassandra:1.56.48, com.netflix.astyanax:astyanax-recipes:1.56.48, com.netflix.astyanax:astyanax-thrift:1.56.48)
[warn]  * jline:jline:1.0 -> 2.11 (caller: com.tinkerpop:gremlin-groovy:3.0.0.M6, org.apache.cassandra:cassandra-all:2.0.8)
[success] Total time: 5 s, completed Feb 20, 2015 6:42:14 PM

As you may have noticed in the above snippet, I was facing dependency version mismatch between three different versions of Netty - `3.6.6.Final`, `3.6.3.Final` and `3.9.3.Final`.

I needed `3.6.6.Final` to be chosen so I used `force()` for the version that I explicitly added to the build (using build.sbt):

libraryDependencies += "io.netty" % "netty" % "3.6.3.Final" force()

With the above line in the build, executing `evicted` showed:

[warn]  * io.netty:netty:(3.9.3.Final, 3.6.6.Final) -> 3.6.3.Final (caller: com.typesafe.netty:netty-http-pipelining:1.1.2, org.apache.cassandra:cassandra-all:2.0.8, com.typesafe.play:play_2.11:2.3.7, com.netflix.astyanax:astyanax-cassandra:1.56.48, my.company:microservice_2.11:0.6.1)

The build is for `my.company:microservice_2.11:0.6.1` that appeared in the above output (the very last library).

Sometimes, however, you should use `exclude` to remove conflicting dependencies as follows:

libraryDependencies ~= { _ map(m => m.exclude("commons-logging", "commons-logging")) }

Problem

Ok so I had my localhost:9000 working just fine one week ago and I am getting this error ever since I moved my project to Eclipse. Even when I have the code in its most basic form, it produces a Netty error that is caught by Play. Here is my error: ``` [info] play - Application started (Prod) [info] play - Listening for HTTP on /0.0.0.0:9000 [error] p.nettyException - Exception caught in Netty java.lang.NoSuchMethodError: org.jboss.netty.handler.codec.http.HttpRequest.headers()Lorg/jboss/netty/handler/codec/http/HttpHeaders; at play.core.server.netty.PlayDefaultUpstreamHandler.getHeaders(PlayDefaultUpstreamHandler.scala:366) ~[na:na] at play.core.server.netty.PlayDefaultUpstreamHandler.messageReceived(PlayDefaultUpstreamHandler.scala:87) ~[na:na] at com.typesafe.netty.http.pipelining.HttpPipeliningHandler.messageReceived(HttpPipeliningHandler.java:62) ~[na:na] at org.jboss.netty.handler.codec.http.HttpContentDecoder.messageReceived(HttpContentDecoder.java:100) ~[na:na] at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:296) ~[na:na] [error] p.nettyException - Exception caught in Netty java.lang.NoSuchMethodError: org.jboss.netty.handler.codec.http.HttpRequest.headers()Lorg/jboss/netty/handler/codec/http/HttpHeaders; at play.core.server.netty.PlayDefaultUpstreamHandler.getHeaders(PlayDefaultUpstreamHandler.scala:366) ~[na:na] at play.core.server.netty.PlayDefaultUpstreamHandler.messageReceived(PlayDefaultUpstreamHandler.scala:87) ~[na:na] at com.typesafe.netty.http.pipelining.HttpPipeliningHandler.messageReceived(HttpPipeliningHandler.java:62) ~[na:na] at org.jboss.netty.handler.codec.http.HttpContentDecoder.messageReceived(HttpContentDecoder.java:100) ~[na:na] at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:296) ~[na:na] [error] p.nettyException - Exception caught in Netty java.lang.NoSuchMethodError: org.jboss.netty.handler.codec.http.HttpRequest.headers()Lorg/jboss/netty/handler/codec/http/HttpHeaders; at play.core.server.netty.PlayDefaultUpstreamHandler.getHeaders(PlayDefaultUpstreamHandler.scala:366) ~[na:na] at play.core.server.netty.PlayDefaultUpstreamHandler.messageReceived(PlayDefaultUpstreamHandler.scala:87) ~[na:na] at com.typesafe.netty.http.pipelining.HttpPipeliningHandler.messageReceived(HttpPipeliningHandler.java:62) ~[na:na] at org.jboss.netty.handler.codec.http.HttpContentDecoder.messageReceived(HttpContentDecoder.java:100) ~[na:na] at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:296) ~[na:na] ``` Here is the basic form code: ``` public class Application extends Controller /*implements Runnable*/ { public static RequestBody print; //private static RemoteWebDriver driver; //private static int ok; public static Result index() { return ok(index.render("Your new application is ready.")); } // Step that prints the object once the JSON is received @BodyParser.Of(BodyParser.Json.class) public static Result receive(){ JsonNode json = request().body().asJson(); if(json == null) // As long as the json is null it will display this return badRequest("Expecting data"); else{ RequestBody body = request().body(); print = body; return ok("Data received.\n" + body.asJson()); } } public static Result show(){ if(print == null){ return ok("Expecting data."); } //(new Thread(new Application())).start(); return ok(print.asJson()); } } ```

Original source