Issue
I cannot read external files from the application image that I created using JLink tool(mvn javaf:jlink
) when the application is running. The external files are placed in the resources folder. This is the error that I got:
ERROR ExecutorOfFiles Script failed to read or load: SampleScript.jsh
java.nio.file.NoSuchFileException: /com.luisosv/com/luisosv/SampleScript.jsh
at java.base/jdk.internal.jrtfs.JrtFileSystem.checkNode(JrtFileSystem.java:494)
at java.base/jdk.internal.jrtfs.JrtFileSystem.getFileContent(JrtFileSystem.java:253)
at java.base/jdk.internal.jrtfs.JrtFileSystem.newByteChannel(JrtFileSystem.java:351)
at java.base/jdk.internal.jrtfs.JrtPath.newByteChannel(JrtPath.java:696)
at java.base/jdk.internal.jrtfs.JrtFileSystemProvider.newByteChannel(JrtFileSystemProvider.java:302)
at java.base/java.nio.file.Files.newByteChannel(Files.java:370)
at java.base/java.nio.file.Files.newByteChannel(Files.java:421)
at java.base/java.nio.file.Files.readAllBytes(Files.java:3205)
at [email protected]/com.luisosv.ExecutorOfFiles.loadSnippetsFromFile(ExecutorOfFiles.java:55)
I'm using the following to read the external file:
String sourceCode = new String(Files.readAllBytes(
Paths.get(
this.getClass().getResource(scriptFileName).toURI())));
However, using the application from command-line it works fine mvn javafx:run
.
I've read that the application image once created, cannot be updated or patched. For any changes, a new application needs to be deployed from https://www.studytrails.com/java/java-9/java-9-jlink/, and I don't know if that is the reason or something else.
Thanks in advance.
Solution
There is a bug in the resource lookup for the jrt filesystem affecting Java versions prior to 13.
When I run the following code snippet:
Path p = Paths.get(Object.class.getResource("Object.class").toURI());
System.out.println(p);
System.out.println(Files.exists(p));
All JDKs from 9 to 12 produce the following output:
/java.base/java/lang/Object.class
false
Starting with JDK 13, the output is
/modules/java.base/java/lang/Object.class
true
Likewise, Files.readAllBytes(Paths.get(Object.class.getResource("Object.class").toURI()))
produces the exception java.nio.file.NoSuchFileException: /java.base/java/lang/Object.class
similar to the exception in your question, showing a path with a module name but no preceding /modules
, for JDK 9 to 12.
So, just switching to JDK 13 or newer would solve your problem.
Note, however, that using
byte[] b = Object.class.getResourceAsStream("Object.class").readAllBytes();
or cleaner
try(InputStream is = Object.class.getResourceAsStream("Object.class")) {
byte[] b = is.readAllBytes();
}
works on all versions from 9 to 14. So I recommend using getResourceAsStream
in the first place instead of the URL
→ URI
→ Path
detour.
That said, you should not use the String(byte[])
constructor. The outcome of this constructor will depend on the current environment, using the system’s default character encoding whereas the actual encoding of your embedded resource will never change.
Use, e.g. new String(b, StandardCharsets.UTF_8)
, or specify whatever your resource is encoded with.
Answered By - Holger
Answer Checked By - David Marino (JavaFixing Volunteer)