@@ -693,13 +693,26 @@ public ProcessBuilder.Redirect newRedirectPipe(FileDescriptor fd) {
693693
694694 /**
695695 * Checks that native access is enabled for this module.
696- * Uses reflection because {@code Module.isNativeAccessEnabled()} is only available on JDK 22+
697- * and {@code Class.getModule()} is only available on JDK 9+.
698- * On older JDKs, the check is skipped (no restrictions exist) .
696+ * JNI native access restrictions are only enforced from JDK 24+, so the check
697+ * is skipped on earlier versions. Uses reflection because
698+ * {@code Module.isNativeAccessEnabled()} is not available on all JDK versions .
699699 *
700700 * @throws UnsupportedOperationException if native access is not enabled
701701 */
702702 static void checkNativeAccess () {
703+ // JNI native access restrictions are only enforced starting from JDK 24.
704+ // Some JDK 21 builds (e.g. 21.0.10) backported Module.isNativeAccessEnabled(),
705+ // but it returns false even though JNI works fine without --enable-native-access.
706+ // See https://github.com/jline/jline3/issues/1689
707+ try {
708+ int version = Integer .parseInt (System .getProperty ("java.specification.version" ));
709+ if (version < 24 ) {
710+ return ;
711+ }
712+ } catch (NumberFormatException e ) {
713+ // JDK 8 uses "1.8" format, which means JDK < 24
714+ return ;
715+ }
703716 try {
704717 Method getModule = Class .class .getMethod ("getModule" );
705718 Object module = getModule .invoke (ExecTerminalProvider .class );
@@ -710,7 +723,7 @@ static void checkNativeAccess() {
710723 "Native access is not enabled for the current module: " + module );
711724 }
712725 } catch (NoSuchMethodException e ) {
713- // JDK < 9 ( no modules) or JDK < 22 (no isNativeAccessEnabled), no restrictions
726+ // Method not available, no native access restrictions
714727 } catch (UnsupportedOperationException e ) {
715728 throw e ;
716729 } catch (ReflectiveOperationException e ) {
0 commit comments