Skip to content

reflection to native check option#61

Merged
NeatGuyCoding merged 4 commits intomainfrom
native-transport
Nov 30, 2025
Merged

reflection to native check option#61
NeatGuyCoding merged 4 commits intomainfrom
native-transport

Conversation

@sanjomo
Copy link
Member

@sanjomo sanjomo commented Nov 28, 2025

Description

Removing reflection as isAvailable present in all OS platforms

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Code refactoring
  • Test improvements
  • Build/tooling changes

Related Issue

Closes #(issue number)

Changes Made

Testing

  • All existing tests pass
  • New tests added for new functionality
  • Tests pass locally with mvn test
  • Integration tests pass (if applicable)

Checklist

  • Code follows project coding standards
  • Self-review completed
  • Code is commented where necessary
  • Documentation updated (if needed)
  • Commit messages follow conventional format
  • No merge conflicts
  • All CI checks pass

Additional Notes

Any additional information, screenshots, or context that reviewers should know.

Summary by CodeRabbit

  • Refactor
    • Transport selection simplified to explicit availability checks for native transports (io_uring, epoll, kqueue) with clearer selection and logging.
    • AUTO mode now logs the chosen transport and reliably falls back to NIO when natives aren’t available.
    • Removed legacy reflection-based loading and dynamic handler discovery in favor of direct, explicit handler factories.
    • Internal surface reduced for a leaner, more maintainable networking layer.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 28, 2025

Walkthrough

Replaced reflection-based native transport loading with explicit availability checks (IoUring.isAvailable(), Epoll.isAvailable(), KQueue.isAvailable()), selecting concrete native channel classes and IoHandler implementations when available and falling back to NioServerSocketChannel/NioIoHandler; removed legacy helper methods and reflection-based loaders.

Changes

Cohort / File(s) Summary
Transport selection & handler initialization
netty-socketio-core/src/main/java/com/socketio4j/socketio/SocketIOServer.java
Removed reflection-based native transport detection and legacy helper methods. Replaced dynamic class loading with explicit isAvailable() checks for IoUring, Epoll, and KQueue and direct selection of IoUringServerSocketChannel / EpollServerSocketChannel / KQueueServerSocketChannel (or NioServerSocketChannel fallback). Replaced createHandler/reflection IoHandler loading with direct IoHandler factories (IoUringIoHandler, EpollIoHandler, KQueueIoHandler, NioIoHandler) and added AUTO-path informational logging for chosen transports.

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Verify AUTO and explicit transport branches pick the correct channel class when availability checks return true.
  • Confirm fallback to NioServerSocketChannel and NioIoHandler preserves prior behavior and startup logging is accurate.
  • Ensure removed helper methods have no remaining references and compilation succeeds.
  • Check IoHandler factory instantiation, typing, and lifecycle (start/stop) integration.

Poem

🐰
I hopped through code to find the way,
Mirrors gone, I choose by day —
IoUring first, then Epoll's cheer,
KQueue next, and Nio near,
A nimble hop — the path is clear. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description check ⚠️ Warning The PR description is incomplete and lacks critical details about the changes made, testing status, and verification completion. Expand the 'Changes Made' section with specific bullet points, confirm testing checklist items (mark as complete or explain why they don't apply), and fill in or reference the related issue number.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title directly summarizes the main change: replacing reflection-based native transport loading with explicit availability checks.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch native-transport

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
netty-socketio-core/src/main/java/com/socketio4j/socketio/SocketIOServer.java (1)

154-196: Critical: Compilation failure due to missing helper methods.

The pipeline is failing because ioUringAvailable(), epollAvailable(), and kqueueAvailable() methods were removed but are still referenced in startAsync(). The refactoring was applied to initGroups() but not here.

Apply this diff to use the direct availability checks consistent with initGroups():

             case IO_URING:
-                if (ioUringAvailable()) {
+                if (IoUring.isAvailable()) {
                     channelClass = loadChannelClass("io.netty.channel.uring.IoUringServerSocketChannel");
                 } else {
                     channelClass = fallback("IO_URING unavailable");
                 }
                 break;

             case EPOLL:
-                if (epollAvailable()) {
+                if (Epoll.isAvailable()) {
                     channelClass = loadChannelClass("io.netty.channel.epoll.EpollServerSocketChannel");
                 } else {
                     channelClass = fallback("EPOLL unavailable");
                 }
                 break;

             case KQUEUE:
-                if (kqueueAvailable()) {
+                if (KQueue.isAvailable()) {
                     channelClass = loadChannelClass("io.netty.channel.kqueue.KQueueServerSocketChannel");
                 } else {
                     channelClass = fallback("KQUEUE unavailable");
                 }
                 break;

             case NIO:
                 channelClass = NioServerSocketChannel.class;
                 break;

             case AUTO:
             default:
-                if (ioUringAvailable()) {
+                if (IoUring.isAvailable()) {
                     channelClass = loadChannelClass("io.netty.channel.uring.IoUringServerSocketChannel");
                     log.info("AUTO selected IO_URING transport");
-                } else if (epollAvailable()) {
+                } else if (Epoll.isAvailable()) {
                     channelClass = loadChannelClass("io.netty.channel.epoll.EpollServerSocketChannel");
                     log.info("AUTO selected EPOLL transport");
-                } else if (kqueueAvailable()) {
+                } else if (KQueue.isAvailable()) {
                     channelClass = loadChannelClass("io.netty.channel.kqueue.KQueueServerSocketChannel");
                     log.info("AUTO selected KQUEUE transport");
                 } else {
                     channelClass = NioServerSocketChannel.class;
                     log.info("AUTO selected NIO transport");
                 }
         }
🧹 Nitpick comments (1)
netty-socketio-core/src/main/java/com/socketio4j/socketio/SocketIOServer.java (1)

246-249: Unused method fallbackFactory.

This method is defined but never called anywhere in the file. It appears to be leftover from the refactoring. Consider removing it to reduce dead code.

-    private IoHandlerFactory fallbackFactory(String msg) {
-        log.warn("{} → Falling back to NIO IoHandler.", msg);
-        return NioIoHandler.newFactory();
-    }
-
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ca5a904 and 2a23555.

📒 Files selected for processing (1)
  • netty-socketio-core/src/main/java/com/socketio4j/socketio/SocketIOServer.java (2 hunks)
🧰 Additional context used
🪛 GitHub Actions: Build PR
netty-socketio-core/src/main/java/com/socketio4j/socketio/SocketIOServer.java

[error] 155-155: Cannot find symbol: method ioUringAvailable() in class SocketIOServer. Command: mvn --batch-mode --errors --fail-at-end verify


[error] 163-163: Cannot find symbol: method epollAvailable() in class SocketIOServer. Command: mvn --batch-mode --errors --fail-at-end verify


[error] 171-171: Cannot find symbol: method kqueueAvailable() in class SocketIOServer. Command: mvn --batch-mode --errors --fail-at-end verify


[error] 184-184: Cannot find symbol: method ioUringAvailable() in class SocketIOServer. Command: mvn --batch-mode --errors --fail-at-end verify


[error] 187-187: Cannot find symbol: method epollAvailable() in class SocketIOServer. Command: mvn --batch-mode --errors --fail-at-end verify


[error] 190-190: Cannot find symbol: method kqueueAvailable() in class SocketIOServer. Command: mvn --batch-mode --errors --fail-at-end verify

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Analyze (java-kotlin)
  • GitHub Check: Analyze (java-kotlin)
🔇 Additional comments (1)
netty-socketio-core/src/main/java/com/socketio4j/socketio/SocketIOServer.java (1)

277-315: Approve the native transport refactoring approach in initGroups.

The switch from reflection-based detection to explicit isAvailable() checks is a sound improvement—cleaner, more maintainable, and avoids reflection overhead. The priority order (IoUring → Epoll → KQueue → NIO) in the AUTO case is appropriate.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
netty-socketio-core/src/main/java/com/socketio4j/socketio/SocketIOServer.java (1)

220-239: Remove unused helper methods.

The methods loadChannelClass, fallback, and fallbackFactory are no longer used after replacing reflection-based loading with explicit availability checks. They should be removed to keep the codebase clean.

-    private Class<? extends ServerChannel> loadChannelClass(String name) {
-        try {
-            @SuppressWarnings("unchecked")
-            Class<? extends ServerChannel> c = (Class<? extends ServerChannel>) Class.forName(name);
-            return c;
-        } catch (Exception ignored) {
-            log.warn("Unable to load native channel {}. Using NIO.", name);
-            return NioServerSocketChannel.class;
-        }
-    }
-
-    private Class<? extends ServerChannel> fallback(String msg) {
-        log.warn("{} → Falling back to NIO.", msg);
-        return NioServerSocketChannel.class;
-    }
-
-    private IoHandlerFactory fallbackFactory(String msg) {
-        log.warn("{} → Falling back to NIO IoHandler.", msg);
-        return NioIoHandler.newFactory();
-    }
-
♻️ Duplicate comments (1)
netty-socketio-core/src/main/java/com/socketio4j/socketio/SocketIOServer.java (1)

298-300: Critical: Default case incorrectly uses IoUringIoHandler.

This issue was flagged in a previous review and remains unresolved. The default case assigns IoUringIoHandler.newFactory(), which will throw an exception at runtime if IoUring is unavailable. This contradicts the safe NIO initialization at line 269.

Apply this diff to fix:

             break;
         default:
-            handler = IoUringIoHandler.newFactory();
+            handler = NioIoHandler.newFactory();
             break;
🧹 Nitpick comments (2)
netty-socketio-core/src/main/java/com/socketio4j/socketio/SocketIOServer.java (2)

156-170: Silent fallback when explicitly requested transport is unavailable.

When a user explicitly configures IO_URING, EPOLL, or KQUEUE transport, but the native transport is unavailable, the code silently falls back to NIO without any warning. This could lead to unexpected behavior where the user believes they're running with native transport.

Consider logging a warning when the explicitly requested transport is unavailable:

             case IO_URING:
                 if (IoUring.isAvailable()) {
                     channelClass = IoUringServerSocketChannel.class;
+                } else {
+                    log.warn("IO_URING transport requested but unavailable, falling back to NIO");
                 }
                 break;
             case EPOLL:
                 if (Epoll.isAvailable()) {
                     channelClass = EpollServerSocketChannel.class;
+                } else {
+                    log.warn("EPOLL transport requested but unavailable, falling back to NIO");
                 }
                 break;
             case KQUEUE:
                 if (KQueue.isAvailable()) {
                     channelClass = KQueueServerSocketChannel.class;
+                } else {
+                    log.warn("KQUEUE transport requested but unavailable, falling back to NIO");
                 }
                 break;

272-286: Add warning logs for unavailable explicit transport requests (consistency with channel selection).

Similar to the channel selection logic in startAsync(), consider adding warning logs when explicitly requested transports are unavailable, for consistency and to help users diagnose configuration issues.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2a23555 and f1b5c60.

📒 Files selected for processing (1)
  • netty-socketio-core/src/main/java/com/socketio4j/socketio/SocketIOServer.java (4 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: build (25) / build
  • GitHub Check: build (21) / build
  • GitHub Check: build (17) / build
  • GitHub Check: Analyze (java-kotlin)
  • GitHub Check: Analyze (java-kotlin)
🔇 Additional comments (1)
netty-socketio-core/src/main/java/com/socketio4j/socketio/SocketIOServer.java (1)

26-28: LGTM!

The imports are correctly aligned with the new explicit availability check approach, importing both the native channel classes and their corresponding availability check utilities.

Also applies to: 53-60

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
netty-socketio-core/src/main/java/com/socketio4j/socketio/SocketIOServer.java (1)

219-238: Remove unused legacy helper methods.

Verification confirms these three helper methods are unused throughout the codebase—only their definitions appear, with no calls to any of them. They are safe to remove:

-    private Class<? extends ServerChannel> loadChannelClass(String name) {
-        try {
-            @SuppressWarnings("unchecked")
-            Class<? extends ServerChannel> c = (Class<? extends ServerChannel>) Class.forName(name);
-            return c;
-        } catch (Exception ignored) {
-            log.warn("Unable to load native channel {}. Using NIO.", name);
-            return NioServerSocketChannel.class;
-        }
-    }
-
-    private Class<? extends ServerChannel> fallback(String msg) {
-        log.warn("{} → Falling back to NIO.", msg);
-        return NioServerSocketChannel.class;
-    }
-
-    private IoHandlerFactory fallbackFactory(String msg) {
-        log.warn("{} → Falling back to NIO IoHandler.", msg);
-        return NioIoHandler.newFactory();
-    }
-
♻️ Duplicate comments (1)
netty-socketio-core/src/main/java/com/socketio4j/socketio/SocketIOServer.java (1)

297-299: Critical: Default case still incorrectly uses IoUringIoHandler.

Despite being marked as addressed in a previous review, the default case still unconditionally assigns IoUringIoHandler.newFactory(), which will throw an exception at runtime if IoUring is not available. This must fall back to NioIoHandler to be safe, consistent with line 268's initialization.

Apply this diff:

         break;
     default:
-        handler = IoUringIoHandler.newFactory();
+        handler = NioIoHandler.newFactory();
         break;
🧹 Nitpick comments (1)
netty-socketio-core/src/main/java/com/socketio4j/socketio/SocketIOServer.java (1)

286-295: Add logging to AUTO case for consistency.

The AUTO case in initGroups() lacks the logging present in the corresponding AUTO case in startAsync(). For consistency and better observability, add logging to indicate which IoHandler is selected.

Apply this diff:

 case AUTO:
     if (IoUring.isAvailable()) {
         handler = IoUringIoHandler.newFactory();
+        log.info("AUTO selected IO_URING IoHandler");
     } else if (Epoll.isAvailable()) {
         handler = EpollIoHandler.newFactory();
+        log.info("AUTO selected EPOLL IoHandler");
     } else if (KQueue.isAvailable()) {
         handler = KQueueIoHandler.newFactory();
+        log.info("AUTO selected KQUEUE IoHandler");
     } else {
         handler = NioIoHandler.newFactory();
+        log.info("AUTO selected NIO IoHandler");
     }
     break;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f1b5c60 and 5c4ef0a.

📒 Files selected for processing (1)
  • netty-socketio-core/src/main/java/com/socketio4j/socketio/SocketIOServer.java (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: build (25) / build
  • GitHub Check: build (21) / build
  • GitHub Check: build (17) / build
  • GitHub Check: Analyze (java-kotlin)
  • GitHub Check: Analyze (java-kotlin)
🔇 Additional comments (2)
netty-socketio-core/src/main/java/com/socketio4j/socketio/SocketIOServer.java (2)

50-60: LGTM! Imports correctly added for native transport support.

The new imports for Epoll, KQueue, and IoUring transports are necessary for the explicit availability checks replacing reflection-based loading.


170-183: LGTM! AUTO transport selection with proper logging.

The AUTO case correctly prioritizes native transports (IoUring → Epoll → KQueue) with appropriate logging for each selection, and falls back to NIO when no native transport is available.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
netty-socketio-core/src/main/java/com/socketio4j/socketio/SocketIOServer.java (1)

289-292: Critical: Default case still incorrectly uses IoUringIoHandler.

The default case unconditionally assigns IoUringIoHandler.newFactory(), which will throw an exception at runtime if IoUring is not available. This should fall back to NioIoHandler to be safe and consistent with line 253's initialization and the channel selection default.

Apply this diff:

-            default:
-                handler = IoUringIoHandler.newFactory();
-                log.info("default transportType {} is selected", handler);
-                break;
+            default:
+                handler = NioIoHandler.newFactory();
+                log.info("NIO IoHandler selected as default");
+                break;
🧹 Nitpick comments (1)
netty-socketio-core/src/main/java/com/socketio4j/socketio/SocketIOServer.java (1)

277-288: Improve logging consistency with channel selection.

The AUTO case logs the handler object, which doesn't clearly indicate which transport was selected. The channel selection AUTO logic (lines 179, 182, 185, 187) explicitly names each transport. Consider improving this log message for consistency.

Apply this diff to match the channel selection style:

             case AUTO:
                 if (IoUring.isAvailable()) {
                     handler = IoUringIoHandler.newFactory();
+                    log.info("AUTO selected IO_URING IoHandler");
                 } else if (Epoll.isAvailable()) {
                     handler = EpollIoHandler.newFactory();
+                    log.info("AUTO selected EPOLL IoHandler");
                 } else if (KQueue.isAvailable()) {
                     handler = KQueueIoHandler.newFactory();
+                    log.info("AUTO selected KQUEUE IoHandler");
                 } else {
                     handler = NioIoHandler.newFactory();
+                    log.info("AUTO selected NIO IoHandler");
                 }
-                log.info(" AUTO selected transportType {}", handler);
                 break;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5c4ef0a and 5d10576.

📒 Files selected for processing (1)
  • netty-socketio-core/src/main/java/com/socketio4j/socketio/SocketIOServer.java (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: build (25) / build
  • GitHub Check: build (21) / build
  • GitHub Check: build (17) / build
  • GitHub Check: Analyze (java-kotlin)
  • GitHub Check: Analyze (java-kotlin)
🔇 Additional comments (2)
netty-socketio-core/src/main/java/com/socketio4j/socketio/SocketIOServer.java (2)

50-60: LGTM! Native transport imports added correctly.

The explicit imports for Epoll, KQueue, and IoUring transport implementations replace the previous reflection-based approach and are properly used throughout the channel and handler selection logic.


152-192: LGTM! Channel selection logic is robust and well-logged.

The explicit availability checks with fallback to NIO are correctly implemented. The logging when native transports are unavailable addresses the concerns from previous reviews and provides good visibility into transport selection.

Copy link
Collaborator

@NeatGuyCoding NeatGuyCoding left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@NeatGuyCoding NeatGuyCoding merged commit 9223df8 into main Nov 30, 2025
8 checks passed
@NeatGuyCoding NeatGuyCoding deleted the native-transport branch November 30, 2025 02:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants