Repository: netty/netty
Issue: NioDatagramChannel can only run under JDK 7+
Labels: defect

Hi,

My Netty version is 4.0.35.Final. I found that `io.netty.channel.socket.nio.NioDatagramChannelConfig` imports `java.nio.channels.NetworkChannel` which is new in JDK 7.

This will cause `NioDatagramChannel` unusable in Android where its Dalvik VM is under Java 1.6. A temporary solution is using `OioDatagramChannel` instead.

How to reproduce:

Just import Netty to an Android app (my Android version: 4.2.2) and try to use `NioDatagramChannel`. Three errors appear during runtime:

```
Could not find class 'java.nio.channels.MembershipKey', referenced from method io.netty.channel.socket.nio.NioDatagramChannel.block
Could not find class 'java.nio.channels.MembershipKey', referenced from method io.netty.channel.socket.nio.NioDatagramChannel.leaveGroup
Could not find class 'java.nio.channels.NetworkChannel', referenced from method io.netty.channel.socket.nio.NioDatagramChannelConfig.<clinit>
```

This issue was also reported in #2816. I think it needs to be addressed in order to make NIO UDP communications compatible with JDK 6.


Issue comments:
@wanganran - Thanks for reporting.

@trustin - Looks like this was introduced in https://github.com/netty/netty/commit/ada61d4985571f5406ea6158b02755d51392ebff . Can you take care?

will take care

I think NioDatagramChannel should report an error: https://github.com/netty/netty/blob/4.1/transport/src/main/java/io/netty/channel/socket/nio/NioDatagramChannel.java#L104

Fixed by https://github.com/netty/netty/pull/5210


Pull request review comments:

Patch that resolved the issue:
diff --git a/transport/src/main/java/io/netty/channel/socket/nio/NioDatagramChannelConfig.java b/transport/src/main/java/io/netty/channel/socket/nio/NioDatagramChannelConfig.java
index 21b9e375c5c..5d1c9f84c3e 100644
--- a/transport/src/main/java/io/netty/channel/socket/nio/NioDatagramChannelConfig.java
+++ b/transport/src/main/java/io/netty/channel/socket/nio/NioDatagramChannelConfig.java
@@ -25,7 +25,6 @@
 import java.net.NetworkInterface;
 import java.net.SocketException;
 import java.nio.channels.DatagramChannel;
-import java.nio.channels.NetworkChannel;
 import java.util.Enumeration;
 
 /**
@@ -78,16 +77,28 @@ class NioDatagramChannelConfig extends DefaultDatagramChannelConfig {
                 throw new Error("cannot locate the IP_MULTICAST_LOOP field", e);
             }
 
+            Class<?> networkChannelClass = null;
             try {
-                getOption = NetworkChannel.class.getDeclaredMethod("getOption", socketOptionType);
-            } catch (Exception e) {
-                throw new Error("cannot locate the getOption() method", e);
+                networkChannelClass = Class.forName("java.nio.channels.NetworkChannel", true, classLoader);
+            } catch (Throwable ignore) {
+                // Not Java 7+
             }
 
-            try {
-                setOption = NetworkChannel.class.getDeclaredMethod("setOption", socketOptionType, Object.class);
-            } catch (Exception e) {
-                throw new Error("cannot locate the setOption() method", e);
+            if (networkChannelClass == null) {
+                getOption = null;
+                setOption = null;
+            } else {
+                try {
+                    getOption = networkChannelClass.getDeclaredMethod("getOption", socketOptionType);
+                } catch (Exception e) {
+                    throw new Error("cannot locate the getOption() method", e);
+                }
+
+                try {
+                    setOption = networkChannelClass.getDeclaredMethod("setOption", socketOptionType, Object.class);
+                } catch (Exception e) {
+                    throw new Error("cannot locate the setOption() method", e);
+                }
             }
         }
         IP_MULTICAST_TTL = ipMulticastTtl;
@@ -173,7 +184,7 @@ protected void autoReadCleared() {
     }
 
     private Object getOption0(Object option) {
-        if (PlatformDependent.javaVersion() < 7) {
+        if (GET_OPTION == null) {
             throw new UnsupportedOperationException();
         } else {
             try {
@@ -185,7 +196,7 @@ private Object getOption0(Object option) {
     }
 
     private void setOption0(Object option, Object value) {
-        if (PlatformDependent.javaVersion() < 7) {
+        if (SET_OPTION == null) {
             throw new UnsupportedOperationException();
         } else {
             try {
@@ -195,5 +206,4 @@ private void setOption0(Object option, Object value) {
             }
         }
     }
-
 }


Test patch: