spring-bootapple-push-notificationsnettynosuchmethoderrorpushy

Pushy APNS http2 protocol - No init method in io.netty.util.concurrent.PromiseCombiner Error


I was facing the following runtime error while using the library

I used the following dependencies in my project

           <dependency>
    <groupId>com.eatthepath</groupId>
    <artifactId>pushy</artifactId>
    <version>0.14.2</version>
</dependency>

<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.48.Final</version>
</dependency>

<dependency>
  <groupId>com.google.code.gson</groupId>
  <artifactId>gson</artifactId>
  <version>2.6</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.0</version>
</dependency>

<dependency>
    <groupId>com.eatthepath</groupId>
    <artifactId>fast-uuid</artifactId>
    <version>0.1</version>
</dependency>

My code implementation is very straight forward following the readme file in https://github.com/jchambers/pushy

        final ApnsClient client = new ApnsClientBuilder()
                .setApnsServer(ApnsClientBuilder.PRODUCTION_APNS_HOST)
                .setClientCredentials(new File(certPath), apnsPassword)
                .build();

for (String deviceToken : deviceTokensList) {
final ApnsPayloadBuilder payloadBuilder = new SimpleApnsPayloadBuilder();
                payloadBuilder.setAlertBody(notificationMessage);

            final String payload = payloadBuilder.build();
            final String token = TokenUtil.sanitizeTokenString(deviceToken);

            final SimpleApnsPushNotification pushNotification = new SimpleApnsPushNotification(token, #invalid_app_bundle#, payload);
            
            final PushNotificationFuture<SimpleApnsPushNotification, PushNotificationResponse<SimpleApnsPushNotification>>
            sendNotificationFuture = client.sendNotification(pushNotification);
              
            try {
                sendNotificationFuture.whenComplete((response, cause) -> {
                    if (response != null) {
                        ConsoleLog.print(isDebug, deviceToken + ", Handle the push notification response as before from here.");
                        insertIntoAPNSThirdPartyServiceLogs(new AppleNotificationEntity(deviceToken, true, source, "Success."));
                    } else {
                        String error = deviceToken + ", " + cause;
                        ConsoleLog.print(isDebug, error);
                        insertIntoAPNSThirdPartyServiceLogs(new AppleNotificationEntity(deviceToken, false, source, error));
                        cause.printStackTrace();
                    }
                });
            } catch (final Exception e) {
                String error = "Failed to send push notification, reason: " + e.getMessage();
                ConsoleLog.print(isDebug, error);
                e.printStackTrace();
                insertIntoAPNSThirdPartyServiceLogs(new AppleNotificationEntity(deviceToken, false, source, error));
            } 
       } // close for loop
       client.close();

Error Logs:

2021-03-26 16:18:31.933 WARN 27557 --- [ntLoopGroup-2-1] io.netty.util.concurrent.DefaultPromise : An exception was thrown by com.eatthepath.pushy.apns.ApnsChannelPool$$Lambda$2619/595971378.operationComplete()
java.lang.NoSuchMethodError: io.netty.util.concurrent.PromiseCombiner.<init>(Lio/netty/util/concurrent/EventExecutor;)V
at com.eatthepath.pushy.apns.ApnsChannelPool.lambda$close$6(ApnsChannelPool.java:247) ~[pushy-0.14.2.jar:na]
at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:511) [netty-common-4.1.23.Final.jar:4.1.23.Final]
at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:485) [netty-common-4.1.23.Final.jar:4.1.23.Final]
at io.netty.util.concurrent.DefaultPromise.access$000(DefaultPromise.java:33) [netty-common-4.1.23.Final.jar:4.1.23.Final]
at io.netty.util.concurrent.DefaultPromise$1.run(DefaultPromise.java:435) [netty-common-4.1.23.Final.jar:4.1.23.Final]
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163) [netty-common-4.1.23.Final.jar:4.1.23.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:404) [netty-common-4.1.23.Final.jar:4.1.23.Final]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:463) [netty-all-4.1.23.Final.jar:4.1.23.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:886) [netty-common-4.1.23.Final.jar:4.1.23.Final]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) [netty-common-4.1.23.Final.jar:4.1.23.Final]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_211]
**java.lang.NoSuchMethodError: io.netty.util.concurrent.PromiseCombiner.<init>(Lio/netty/util/concurrent/EventExecutor;)V**
at com.eatthepath.pushy.apns.ApnsClientHandler.writePushNotification(ApnsClientHandler.java:217)
at com.eatthepath.pushy.apns.ApnsClientHandler.write(ApnsClientHandler.java:175)
at io.netty.channel.AbstractChannelHandlerContext.invokeWrite0(AbstractChannelHandlerContext.java:738)
at io.netty.channel.AbstractChannelHandlerContext.invokeWriteAndFlush(AbstractChannelHandlerContext.java:801)
at io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:814)
at io.netty.channel.AbstractChannelHandlerContext.writeAndFlush(AbstractChannelHandlerContext.java:794)
at io.netty.channel.AbstractChannelHandlerContext.writeAndFlush(AbstractChannelHandlerContext.java:831)
at io.netty.channel.DefaultChannelPipeline.writeAndFlush(DefaultChannelPipeline.java:1071)
at io.netty.channel.AbstractChannel.writeAndFlush(AbstractChannel.java:300)
at com.eatthepath.pushy.apns.ApnsClient.lambda$sendNotification$1(ApnsClient.java:205)
at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:511)
at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:485)
at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:424)
at io.netty.util.concurrent.DefaultPromise.trySuccess(DefaultPromise.java:103)
at com.eatthepath.pushy.apns.ApnsChannelPool.lambda$acquireWithinEventExecutor$2(ApnsChannelPool.java:156)
at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:511)
at io.netty.util.concurrent.DefaultPromise.notifyListeners0(DefaultPromise.java:504)
at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:483)
at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:424)
at io.netty.util.concurrent.DefaultPromise.trySuccess(DefaultPromise.java:103)
at com.eatthepath.pushy.apns.ApnsClientHandler.onSettingsRead(ApnsClientHandler.java:396)
at io.netty.handler.codec.http2.DefaultHttp2ConnectionDecoder$FrameReadListener.onSettingsRead(DefaultHttp2ConnectionDecoder.java:423)
at io.netty.handler.codec.http2.DefaultHttp2ConnectionDecoder$PrefaceFrameListener.onSettingsRead(DefaultHttp2ConnectionDecoder.java:635)
at io.netty.handler.codec.http2.DefaultHttp2FrameReader.readSettingsFrame(DefaultHttp2FrameReader.java:542)
at io.netty.handler.codec.http2.DefaultHttp2FrameReader.processPayloadState(DefaultHttp2FrameReader.java:263)
at io.netty.handler.codec.http2.DefaultHttp2FrameReader.readFrame(DefaultHttp2FrameReader.java:160)
at io.netty.handler.codec.http2.DefaultHttp2ConnectionDecoder.decodeFrame(DefaultHttp2ConnectionDecoder.java:118)
at io.netty.handler.codec.http2.Http2ConnectionHandler$FrameDecoder.decode(Http2ConnectionHandler.java:390)
at io.netty.handler.codec.http2.Http2ConnectionHandler$PrefaceDecoder.decode(Http2ConnectionHandler.java:254)
at io.netty.handler.codec.http2.Http2ConnectionHandler.decode(Http2ConnectionHandler.java:450)
at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:489)
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:428)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:265)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:286)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.handler.flush.FlushConsolidationHandler.channelRead(FlushConsolidationHandler.java:147)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1407)
at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1177)
at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1221)
at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:489)
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:428)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:265)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1434)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:965)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:645)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:580)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:497)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:459)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:886)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)

This problem is being produced in the whenComplete method and returning null response with the above cause

sendNotificationFuture.whenComplete((response, cause) -> {
if (response != null) {
} else {
// here
}
}

Solution

  • After checking the netty-common version, I noticed that the netty version is not 4.1.48.Final And I am using Spring version 2.0.1.RELEASE which required 4.1.23.Final netty version in the main project that include the Jar file that contains the Pushy library.

    So I added the following dependency that fixed the problem in the main project that override the existing netty version

    
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-common</artifactId>
            <version>4.1.48.Final</version>
        </dependency>
    

    Github ticket