Конфликт между игрой! Framework 2.5 и gRPC 0,13

Play 2.5.0 использует Netty 4.0.33, а gRPC требует Netty 4.1.0 (для поддержки http2), что вызывает следующее исключение:

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

После того, как я удаляю все коды gRPC, он снова работает.

Есть ли какое-нибудь быстрое решение, которое я могу попробовать сейчас? Спасибо!

3 ответа

Решение

Редактировать:

Play 2.6.0 был выпущен и использует Netty 4.1.

ТЛ; др

Play 2.5.0 и gRPC несовместимы из-за двоичной несовместимости между Netty 4 и Netty 4.1.


Вот почему он не работает с Play 2.5.0, но работает с Play 2.4.0:

Play 2.5.0 использует версию Netty 4.0.33.Final, который объявлен (транзитивно через netty-реактивный поток версии 1.0.2) следующим образом:

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

Версия 4.0.33.Final выселено версией 4.0.34.Final который был транзитивно добавлен async-http-client, и это зависимости netty, используемые 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

Для игры 2.4.6 с другой стороны требуется только следующая зависимость от netty:

io.netty:netty:3.8.0.Final

Таким образом, в то время как Play 2.5.0 зависит от множества небольших пакетов нетти, Play 2.4.6 зависит только от одного пакета нетти. Это связано с тем, что Netty 4 изменила структуру проекта, чтобы разделить проект на несколько подпроектов, чтобы пользователь мог добавить только необходимые функции из Netty. И что еще более важно, "имя пакета Netty было изменено с org.jboss.netty на io.netty".

Почему эти изменения важны здесь:

  1. Нет конфликта зависимостей между gRPC с 2.4.6, потому что gRPC не требует зависимости io.netty:nettyДаже транзитивно. Из-за этого нет выселения.
  2. На уровне классов нет конфликта, потому что у классов были разные имена пакетов (org.jboss.netty а также io.netty), а затем иметь разные полные имена. Они рассматриваются как разные классы.

Существуют конфликты с Play 2.5.0, потому что Netty 4 и Netty 4.1 имеют одинаковые зависимости (тогда 4.0.34 вытесняется с помощью 4.1) и потому что - поскольку теперь у нас одинаковые полные квалифицированные имена классов между этими двумя версиями, возникает несовместимость двоичных файлов,

Это длинное объяснение того, что сейчас нет способа заставить gRPC и Play 2.5.0 работать вместе с Netty. Даже если вы решите использовать серверную часть Akka HTTP, существует вероятность конфликта с Play WS.

Вы также можете использовать maven-shade-plugin для перемещения имен пакетов netty, чтобы они не конфликтовали с более ранней версией.

Посмотрите библиотеку ядра couchbase jvm для примера https://github.com/couchbase/couchbase-jvm-core.

Я также сталкивался с этим в Play с использованием Java. Используете ли вы клиентский или серверный интерфейс gRPC с сервером Play? Если вы просто используете только клиента, вы можете преодолеть это, используя версию клиента OKHTTP вместо той, которая основана на Netty.

https://mvnrepository.com/artifact/io.grpc/grpc-okhttp

Если вы используете сервер, я думаю, вам не повезло. Вы можете попытаться исключить Netty из gRPC и надеяться, что версии Play достаточно. Просто добавьте excludeAll ExclusionRule(organization = "io.netty") в импорт gRPC.

Вот тема в списке рассылки play по этой теме, но пока нет никаких изменений в теме: https://groups.google.com/forum/

Другие вопросы по тегам