Repository: netty/netty
Issue: Micronaut Graal native-images doesn't work anymore with Netty 4.1.35+

### Expected behavior

I'm trying to upgrade Micronaut to use Netty 4.1.35 or later and it should be possible to build Micronaut GraalVM native-images with that Netty version.
I know that Netty introduced Graal support in 4.1.36 but it uses the old approach, meaning that it's compatible with Graal pre-19.0.0 version. I was hoping to send a PR here to upgrade Netty to support Graal 19.0.0 (and 19.0.2 now), but first this need to be fixed.

### Actual behavior

The application fails when starting the native image.

### Steps to reproduce

It's not easy to reproduce the issue because you need to upgrade Netty version in Micronaut, build it locally and then create a native-image using that Micronaut version.

When staring the application the error is:

```$ ./basic-app
00:00:28.269 [main] ERROR i.m.h.server.netty.NettyHttpServer - Error starting Micronaut server: io.netty.bootstrap.ServerBootstrap$1.channelRegistered(io.netty.channel.ChannelHandlerContext)
java.lang.NoSuchMethodException: io.netty.bootstrap.ServerBootstrap$1.channelRegistered(io.netty.channel.ChannelHandlerContext)
	at java.lang.Class.getMethod(DynamicHub.java:987)
	at io.netty.channel.ChannelHandlerMask$2.run(ChannelHandlerMask.java:166)
	at io.netty.channel.ChannelHandlerMask$2.run(ChannelHandlerMask.java:163)
	at java.security.AccessController.doPrivileged(AccessController.java:83)
	at io.netty.channel.ChannelHandlerMask.isSkippable(ChannelHandlerMask.java:163)
	at io.netty.channel.ChannelHandlerMask.mask0(ChannelHandlerMask.java:91)
	at io.netty.channel.ChannelHandlerMask.mask(ChannelHandlerMask.java:76)
	at io.netty.channel.AbstractChannelHandlerContext.<init>(AbstractChannelHandlerContext.java:104)
	at io.netty.channel.DefaultChannelHandlerContext.<init>(DefaultChannelHandlerContext.java:26)
	at io.netty.channel.DefaultChannelPipeline.newContext(DefaultChannelPipeline.java:120)
	at io.netty.channel.DefaultChannelPipeline.addLast(DefaultChannelPipeline.java:204)
	at io.netty.channel.DefaultChannelPipeline.addLast(DefaultChannelPipeline.java:385)
	at io.netty.channel.DefaultChannelPipeline.addLast(DefaultChannelPipeline.java:372)
	at io.netty.bootstrap.ServerBootstrap.init(ServerBootstrap.java:169)
	at io.netty.bootstrap.AbstractBootstrap.initAndRegister(AbstractBootstrap.java:321)
	at io.netty.bootstrap.AbstractBootstrap.doBind(AbstractBootstrap.java:282)
	at io.netty.bootstrap.AbstractBootstrap.bind(AbstractBootstrap.java:278)
	at io.netty.bootstrap.AbstractBootstrap.bind(AbstractBootstrap.java:253)
	at io.micronaut.http.server.netty.NettyHttpServer.bindServerToHost(NettyHttpServer.java:421)
	at io.micronaut.http.server.netty.NettyHttpServer.start(NettyHttpServer.java:318)
	at io.micronaut.http.server.netty.NettyHttpServer.start(NettyHttpServer.java:96)
	at io.micronaut.runtime.Micronaut.lambda$start$2(Micronaut.java:75)
	at java.util.Optional.ifPresent(Optional.java:159)
	at io.micronaut.runtime.Micronaut.start(Micronaut.java:73)
	at io.micronaut.runtime.Micronaut.run(Micronaut.java:303)
	at io.micronaut.runtime.Micronaut.run(Micronaut.java:289)
	at example.micronaut.Application.main(Application.java:8)
00:00:28.272 [main] ERROR io.micronaut.runtime.Micronaut - Error starting Micronaut server: Unable to start Micronaut server on port: 8080
io.micronaut.http.server.exceptions.ServerStartupException: Unable to start Micronaut server on port: 8080
	at io.micronaut.http.server.netty.NettyHttpServer.bindServerToHost(NettyHttpServer.java:446)
	at io.micronaut.http.server.netty.NettyHttpServer.start(NettyHttpServer.java:318)
	at io.micronaut.http.server.netty.NettyHttpServer.start(NettyHttpServer.java:96)
	at io.micronaut.runtime.Micronaut.lambda$start$2(Micronaut.java:75)
	at java.util.Optional.ifPresent(Optional.java:159)
	at io.micronaut.runtime.Micronaut.start(Micronaut.java:73)
	at io.micronaut.runtime.Micronaut.run(Micronaut.java:303)
	at io.micronaut.runtime.Micronaut.run(Micronaut.java:289)
	at example.micronaut.Application.main(Application.java:8)
Caused by: java.lang.NoSuchMethodException: io.netty.bootstrap.ServerBootstrap$1.channelRegistered(io.netty.channel.ChannelHandlerContext)
	at java.lang.Class.getMethod(DynamicHub.java:987)
	at io.netty.channel.ChannelHandlerMask$2.run(ChannelHandlerMask.java:166)
	at io.netty.channel.ChannelHandlerMask$2.run(ChannelHandlerMask.java:163)
	at java.security.AccessController.doPrivileged(AccessController.java:83)
	at io.netty.channel.ChannelHandlerMask.isSkippable(ChannelHandlerMask.java:163)
	at io.netty.channel.ChannelHandlerMask.mask0(ChannelHandlerMask.java:91)
	at io.netty.channel.ChannelHandlerMask.mask(ChannelHandlerMask.java:76)
	at io.netty.channel.AbstractChannelHandlerContext.<init>(AbstractChannelHandlerContext.java:104)
	at io.netty.channel.DefaultChannelHandlerContext.<init>(DefaultChannelHandlerContext.java:26)
	at io.netty.channel.DefaultChannelPipeline.newContext(DefaultChannelPipeline.java:120)
	at io.netty.channel.DefaultChannelPipeline.addLast(DefaultChannelPipeline.java:204)
	at io.netty.channel.DefaultChannelPipeline.addLast(DefaultChannelPipeline.java:385)
	at io.netty.channel.DefaultChannelPipeline.addLast(DefaultChannelPipeline.java:372)
	at io.netty.bootstrap.ServerBootstrap.init(ServerBootstrap.java:169)
	at io.netty.bootstrap.AbstractBootstrap.initAndRegister(AbstractBootstrap.java:321)
	at io.netty.bootstrap.AbstractBootstrap.doBind(AbstractBootstrap.java:282)
	at io.netty.bootstrap.AbstractBootstrap.bind(AbstractBootstrap.java:278)
	at io.netty.bootstrap.AbstractBootstrap.bind(AbstractBootstrap.java:253)
	at io.micronaut.http.server.netty
```

As Graeme Rocher mentioned in our issue https://github.com/micronaut-projects/micronaut-core/pull/1802#issuecomment-504642431 there is a breaking change introduced in Netty 4.1.35 here https://github.com/netty/netty/commit/8f7ef1cabb5442584e56a9e79bcb9696bc572a94#diff-006d8822b20e6bcf0e9f5f2470153807R166:

![image](https://user-images.githubusercontent.com/559192/60031863-c4616c00-96a5-11e9-844d-5530156d21db.png)

### Minimal yet complete reproducer code (or URL to code)

Not simple to reproduce. If you can't figure it out we can publish a specific snapshot version with the upgraded Netty dependency and the Micronaut Graal application that reproduces the issue.

### Netty version

4.1.35 and later.

### JVM version (e.g. `java -version`)

```
openjdk version "1.8.0_212"
OpenJDK Runtime Environment (build 1.8.0_212-20190523183340.buildslave.jdk8u-src-tar--b03)
OpenJDK 64-Bit GraalVM CE 19.0.2 (build 25.212-b03-jvmci-19-b04, mixed mode)
```

### OS version (e.g. `uname -a`)

```
Linux nobita 4.18.0-20-generic #21~18.04.1-Ubuntu SMP Wed May 8 08:43:37 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
```

Issue comments:
The issue is that on this line

https://github.com/netty/netty/commit/8f7ef1cabb5442584e56a9e79bcb9696bc572a94#diff-006d8822b20e6bcf0e9f5f2470153807R166

The call to retrieve the method is returning `null` on GraalVM. The issue has a knock on effect as previous versions of Netty allows handlers to not be registered for reflection, but since the change all handlers used by netty have to be registered for reflective access. It would be better if this was not the case and instead a null check is added to the method call.
@graemerocher sure we can add a null check but still I wonder if this is even "valid" to return null in terms of API. Shouldn't you better throw an exception if you can not find the method (for whatever reason). 
@graemerocher also please feel free to send a PR for the extra null check. 
Will do thanks 
@graemerocher <3
Thanks!
@graemerocher I'm also running into this issue. I'm not sure I fully understand why this `NoSuchMethodException` is being thrown and why it's fine to ignore it. In a vert.x based application I compiled with graalvm native, I'm getting hundreds of these reflective errors when starting up because I have the `io.netty` level set to `FINE`.

Are these errors expected? I'm using `4.1.49` so the netty version I'm using includes this fix. Thanks in advance!

Pull request review comments:

Patch that resolved the issue:
diff --git a/transport/src/main/java/io/netty/channel/ChannelHandlerMask.java b/transport/src/main/java/io/netty/channel/ChannelHandlerMask.java
index ef384433280..526006a84e3 100644
--- a/transport/src/main/java/io/netty/channel/ChannelHandlerMask.java
+++ b/transport/src/main/java/io/netty/channel/ChannelHandlerMask.java
@@ -175,7 +175,7 @@ public Boolean run() throws Exception {
                         "Class {} missing method {}, assume we can not skip execution", handlerType, methodName, e);
                     return false;
                 }
-                return m.isAnnotationPresent(Skip.class);
+                return m != null && m.isAnnotationPresent(Skip.class);
             }
         });
     }


Test patch: