JEP 330

Peter Levart peter.levart at gmail.com
Tue Jun 5 08:11:57 UTC 2018


Hi,

On 06/03/2018 09:45 PM, Jonathan Gibbons wrote:
>> As an idealist, I might want Class.getResourceAsStream to return
>> the contents of a side file to the script file.  But it's more likely to
>> return null, given the strategy of compiling the script into a temporary
>> artifact in an undisclosed location.
> Class.getResourceAsStream will find items on the classpath used by the VM.

...this will find the "content" of items on the classpath. If one wants 
to find the "location" (i.e. URL) Class.getResource() will return it.

But in the context of java launcher executing a "source" file, searching 
for location of the executing class would return some URL pointing to 
"memory" where the source was compiled to, wouldn't it? Not something 
that could be used to locate "side" files - files in the same directory 
as source/script file.

I know that the main purpose of this JEP is to provide a stepping stone 
for beginners in the Java world. But the experienced will always find it 
also as a means to write executable scripts in Java. For the later it is 
important that the feature allows writing scripts that are as portable 
as possible. I see one obstacle to achieve that. The location of java 
launcher executable is not standardized across platforms (even UNIX 
platforms). So hard-coding absolute path in the shebang script is bound 
to create non portable script. Locating the java launcher using PATH 
would be much more portable. Java, if installed properly, is usually 
added to PATH. The standard way to locate script interpreters using PATH 
is by indirection through /bin/env utility:

#!/bin/env java

public class Cmd {
     public static void main(String ...args) {
         ...
     }
}


While this works and passes script arguments to java executable as 
intended, it does not work when combined with additional options passed 
to script interpreter (like "--source 11") in the script itself:

#!/bin/env java --source 11

public class Cmd {
     public static void main(String ...args) {
         ...
     }
}


At least on Linux, env tries to locate executable called "java --source 
11" on the PATH and bails out with:

/bin/env: ‘java --source 11’: No such file or directory


So the best bet here is a hybrid script that starts as a bash script 
which "computes" the environment and paths and then executes java 
launcher with all required arguments. One way to do that is using "here" 
documents. Stuart Marks provided an example:

#!/bin/bash
exec java --source 11 /dev/fd/3 "$@" 3<<EOF
public class Hello {
     public static void main(String[] args) {
         String name = System.console().readLine("Please enter your 
name: ");
         System.console().printf("Hello, %s!%n", name);
     }
}
EOF

This script uses an OS feature where special file /dev/fd/N when opened, 
provides a file handle dup-ed from the file handle N. I don't know how 
portable this is across UNIX-es. Linux and Mac at least do have it and 
use same paths. What about other UNIX-like OS-es where OpenJDK is built? 
If for some OS the feature is not available, then java launcher could 
help here by interpreting a special syntax of file specified as 
"/dev/fd/N" and executing the necessary dup itself on such OS.


What do you think?

Regards, Peter



More information about the compiler-dev mailing list