Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conflict between Play! Framework 2.5 and gRPC 0.13

Play 2.5.0 uses Netty 4.0.33, while gRPC requires Netty 4.1.0 (for http2 support), which causes the following exception:

[error] p.c.s.n.PlayRequestHandler - Exception caught in Netty
java.lang.AbstractMethodError: null
    at io.netty.util.ReferenceCountUtil.touch(ReferenceCountUtil.java:73)
    at io.netty.channel.DefaultChannelPipeline.touch(DefaultChannelPipeline.java:84)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:154)
    at com.typesafe.netty.http.HttpStreamsHandler.channelRead(HttpStreamsHandler.java:131)
    at com.typesafe.netty.http.HttpStreamsServerHandler.channelRead(HttpStreamsServerHandler.java:96)
    at io.netty.channel.ChannelHandlerInvokerUtil.invokeChannelReadNow(ChannelHandlerInvokerUtil.java:83)
    at io.netty.channel.DefaultChannelHandlerInvoker.invokeChannelRead(DefaultChannelHandlerInvoker.java:154)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:154)
    at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103)
    at io.netty.channel.ChannelHandlerInvokerUtil.invokeChannelReadNow(ChannelHandlerInvokerUtil.java:83)
[error] p.c.s.n.PlayRequestHandler - Exception caught in Netty
java.util.NoSuchElementException: http-handler-body-publisher
    at io.netty.channel.DefaultChannelPipeline.getContextOrDie(DefaultChannelPipeline.java:1050)
    at io.netty.channel.DefaultChannelPipeline.remove(DefaultChannelPipeline.java:379)
    at com.typesafe.netty.http.HttpStreamsHandler.handleReadHttpContent(HttpStreamsHandler.java:191)
    at com.typesafe.netty.http.HttpStreamsHandler.channelRead(HttpStreamsHandler.java:167)
    at com.typesafe.netty.http.HttpStreamsServerHandler.channelRead(HttpStreamsServerHandler.java:96)
    at io.netty.channel.ChannelHandlerInvokerUtil.invokeChannelReadNow(ChannelHandlerInvokerUtil.java:83)
    at io.netty.channel.DefaultChannelHandlerInvoker.invokeChannelRead(DefaultChannelHandlerInvoker.java:154)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:154)
    at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103)
    at io.netty.channel.ChannelHandlerInvokerUtil.invokeChannelReadNow(ChannelHandlerInvokerUtil.java:83)

After I remove all gRPC codes, it works again.

Is there any quick fix that I can try now? Thanks!

like image 582
DANG Fan Avatar asked Mar 06 '16 14:03

DANG Fan


1 Answers

Edit:

Play 2.6.0 was released, and it is using Netty 4.1.

tl;dr

Play 2.5.0 and gRPC are not compatible due to binary incompatibilities between Netty 4 and Netty 4.1.


Here is why it doesn't work with Play 2.5.0 but works with Play 2.4.0:

Play 2.5.0 uses Netty version 4.0.33.Final, which is declared (transitively via netty-reactive-streams version 1.0.2) like this:

<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-handler</artifactId>
    <version>4.0.33.Final</version>
</dependency>
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-codec-http</artifactId>
    <version>4.0.33.Final</version>
</dependency>

Version 4.0.33.Final is evicted by version 4.0.34.Final which was added transitively by async-http-client and these are the netty dependencies used by Play 2.5.0:

io.netty:netty-buffer:4.0.34.Final
io.netty:netty-codec-http:4.0.34.Final
io.netty:netty-codec:4.0.34.Final
io.netty:netty-common:4.0.34.Final
io.netty:netty-handler:4.0.34.Final
io.netty:netty-transport:4.0.34.Final

Play 2.4.6, on the other side, requires just the following netty dependency:

io.netty:netty:3.8.0.Final

So, while Play 2.5.0 depends on a lot of smaller netty packages, Play 2.4.6 depends just on a single netty package. That is because Netty 4 changed the project structure to split the project into multiple subprojects so that a user can add just the necessary features from Netty. And even more important, "the package name of Netty has been changed from org.jboss.netty to io.netty".

Why are these changes both relevant here?

  1. There is no dependency conflict between gRPC with 2.4.6 because gRPC does not require dependency io.netty:netty, not even transitively. Because of that, there is no eviction.
  2. There is no conflict at the class level because the classes have different packages names (org.jboss.netty and io.netty) and then distinct full qualified names. Therefore, they are treated as different classes.

There are conflicts with Play 2.5.0 because Netty 4 and Netty 4.1 have both the same dependencies artifactId (then 4.1 version evicts 4.0.34) and because - since we now have the same full qualified class names between these two versions - binaries incompatibilities arise.

That is a long explanation to say that there is no way to make gRPC and Play 2.5.0 work together right now with Netty. Even if you decide to use Akka HTTP server backend, there is a chance of conflict with Play WS.

like image 177
marcospereira Avatar answered Dec 21 '22 22:12

marcospereira