HaxeFoundation / haxe

Haxe - The Cross-Platform Toolkit
https://haxe.org
6.2k stars 657 forks source link

[jvm/java] sys.io.Process.getPid() does not work on Windows nor when using Java 17 #10938

Open sebthom opened 1 year ago

sebthom commented 1 year ago

sys.io.Process.getPid() relies on reflecting on an internal pid field which is only available for Java on Linux. As of Java 9 the java.lang.Process class was extended by a long pid() method returning the pid of a process. It would be great if sys.io.Process.getPid() would delegate to the java.lang.Process.pid() for the jvm/java targets and only fallback to reflecting on the internal pid file in case Java 8 is used.


Executing sys.io.Process.getPid() on Java 11 or newer results in:

Exception in thread "main" java.lang.ClassCastException: class haxe.lang.Closure cannot be cast to class java.lang.Number (haxe.lang.Closure is in unnamed module of loader 'app'; java.lang.Number is in module java.base of loader 'bootstrap')
  at haxe.lang.Runtime.toInt(Runtime.java:127)
  at sys.io.Process.getPid(Process.java:218)

Changing sys.io.Process.getPid() to:

public function getPid():Int {
    if (Reflect.hasField(proc, "pid")) {
        final pid:Dynamic = Reflect.field(proc, "pid");
        if (Type.typeof(pid) == TFunction)
            return Reflect.callMethod(proc, pid, []);
        return pid;
    }
    return -1;
}
  1. works with Java 8 and 11 using the java target, but emits the following warnings on Java 11:
    WARNING: An illegal reflective access operation has occurred
    WARNING: Illegal reflective access by haxe.lang.Runtime (file:/D:/workspaces/projects-haxe/haxe-concurrent/target/java/TestRunner-Debug.jar) to method java.lang.ProcessImpl.pid()
    WARNING: Please consider reporting this to the maintainers of haxe.lang.Runtime
    WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
    WARNING: All illegal access operations will be denied in a future release
  2. fails using the jvm target:
    java.lang.IllegalAccessException: class haxe.jvm.Closure cannot access a member of class java.lang.ProcessImpl (in module java.base) with modifiers "public"
  3. fails on Java 17, where it throws:
    java.lang.reflect.InaccessibleObjectException: Unable to make public long java.lang.ProcessImpl.pid() accessible: module java.base does not "opens java.lang" to unnamed module @1ef7fe8e

I also tried playing around with untyped __java__ but could not get anyting working, also it does not seem to support the jvm target.

Any help is greatly appreciated.

sebthom commented 1 year ago

As a workaround I am now doing:

@:native("java.lang.Process")
extern class Java9Process {
    public function pid(): haxe.Int64;
}

@:access(sys.io.Process.proc)
public function getPid(sys.io.Process p) {
    var pid:Int = -1;
    #if java
        try { pid = process.getPid(); } catch (ex:Dynamic) { } // works on Java 8 (except Windows)
        if (pid == -1) try { // works on Java 9+ incl. Windows
            var p:Java9Process = cast process.proc;
            pid = cast(p.pid(), Int);
        } catch (ex:Dynamic) { }
    #else
        pid = p.getPid();
    #end
    return pid;
}