Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 11: Executing Source File via Shebang is not working

Tags:

I wanted to check out some new features of java 11 which was released two days ago. JEP 330 states that I could launch a Java-Source-Code-Program without compiling. It should also support the usage of Shebang-Files.

Hence I have written this small Hello-World Program Test.java:

#!/opt/java/jdk-11/bin/java --source 11

public class Test
{
    public static void main(String[] args)
    {
        System.out.println("Hello World!");
    }
}

I downloaded JDK 11 and extracted it to /opt/java. Hence the Shebang itself is working. I.e. executing /opt/java/jdk-11/bin/java --version gives me

openjdk 11 2018-09-25
OpenJDK Runtime Environment 18.9 (build 11+28)
OpenJDK 64-Bit Server VM 18.9 (build 11+28, mixed mode)

After making Test.java executable (using chmod +x Test.java) the execution is failing. I.e. ./Test.java gives me:

./Test.java:1: error: illegal character: '#'
#!/opt/java/jdk-11/bin/java --source 11
^
./Test.java:1: error: class, interface, or enum expected
#!/opt/java/jdk-11/bin/java --source 11
^
2 errors
error: compilation failed

As soon as I remove the Shebang-Line from Test.java and start it with /opt/java/jdk-11/bin/java --source 11 Test.java everything is working like a charm and I get the expected output: Hello World!

My machine is running Ubuntu 17.04. I have linked javac to the one from JDK 11 (i.e. executing javac -version gives javac 11).

like image 359
mam10eks Avatar asked Sep 27 '18 06:09

mam10eks


3 Answers

The file name must not end with .java in order for the java executable to ignore the shebang line. You can use a different extension, or just have no extension at all (which is what they do in the JEP example and is what I would recommend).

From JEP 330 (emphasis added):

When the launcher reads the source file, if the file is not a Java source file (i.e. it is not a file whose name ends with .java) and if the first line begins with #!, then the contents of that line up to but not including the first newline are ignored when determining the source code to be passed to the compiler. The content of the file that appears after the first line must consist of a valid CompilationUnit as defined by §7.3 in the edition of the Java Language Specification that is appropriate to the version of the platform given in the --source option, if present, or the version of the platform being used to run the program if the --source option is not present.

It doesn't need to end with ".sh" specifically; also, that's potentially misleading because the file is not actually a shell script.

like image 53
Miles Avatar answered Nov 03 '22 07:11

Miles


A bit of trial and error gave me the correct solution. It was the file extension .java which causes those problems.

I.e. if I rename the file to Test.sh everything is working.

Here is a complete Hello-World-Shebang-Example:

Create a File Test.sh with content like

#!/opt/java/jdk-11/bin/java --source 11

public class Test
{
    public static void main(String[] args)
    {
        System.out.println("Hello World!");
    }
}

Make it executable (i.e. chmod +x Test.sh).

Last but not least execute it using ./Test.sh

like image 40
mam10eks Avatar answered Nov 03 '22 09:11

mam10eks


According to the JEP you've linked to (see the shebang files section), the shebang file is to be used to launch the java process, not to be used as a parameter for java:

A shebang file to invoke the Java launcher using source-file mode must begin with something like:

#!/path/to/java --source version

For example, we could take the source code for a "Hello World" program, and put it in a file called hello, after an initial line of #!/path/to/java --source 10, and then mark the file as executable. Then, if the file is in the current directory, we could execute it with:

$ ./hello

In other words, what you want to do is rather make Test.java executable. You'd also have to rename it since it won't work as shebang and strip first line when it's named *.java.

$ move Test.java test
$ chmod +x test
$ ./test 

This will launch shebang processor which will strip first line and pass the rest of the script to /path/to/java and Java will compile the script and run the main method.

like image 41
ernest_k Avatar answered Nov 03 '22 09:11

ernest_k