1

Context: I successfully parse a json file while debugging/running locally in my Windows PC that way

import com.fasterxml.jackson.core.JsonFactory
import com.fasterxml.jackson.core.JsonParser
import java.io.File
import java.nio.file.Paths

...

val basePath = Paths.get("").toAbsolutePath().toString()

val parser: JsonParser = JsonFactory().createParser(File("$basePath/app/src/main/resources/support/certain-file.json"))

When I deployed it to either docker or AWS I get this error

 /app/src/main/resources/support/certain-file.json (No such file or directory)

Is there a more reliable way to "navigate" to a file placed in resources folder? I mean someway it wouldn't be affected either it is Windows/Linux/Kubernetes/etc?

Jim C
  • 3,957
  • 25
  • 85
  • 162
  • it depends on where that file is. in `src/main/resources`? – Eugene Jan 27 '21 at 21:34
  • Absolute path should work. Are you sure that file is present in the image running on AWS? No volume that could be mounted on top of a parent folder? – SYN Jan 27 '21 at 21:34
  • @Eugene, yes it is under resources folder – Jim C Jan 27 '21 at 22:46
  • 2
    The usual way to access resources is via the classpath, not a filename.  See e.g. [this question](/questions/42739807/how-to-read-a-text-file-from-resources-in-kotlin). – gidds Jan 27 '21 at 23:09
  • @gidds thanks, now it is working. Kindly, could you give me an overview why MyCurrentClass::class.java.getResource("/...").readText() works in both Windows as Docker while my above approach based on java.io.File and java.nio.file.Paths only works on Windows? Maybe you can point why you think classpath is the usual/better way and then I will pick your answer up. – Jim C Jan 28 '21 at 05:00

1 Answers1

2

The usual way to access resource files is via the classpath, not by going directly to the filesystem.

There are several advantages to this:

  • The resources will usually be deployed automatically, along with your compiled code; no need for manual copying.  (Maven and Gradle usually know to treat the src/main/resources folder this way.)
  • If you build the application as a .jar/.war file, the resources will get included in that.  (Your code doesn't need to know or care that they're in an archive; as long as you access the resource as a stream, loading just works.)
  • The application isn't tied to a particular directory layout or OS; it can run in any directory on any machine.
  • You can override files.  Because the classpath can give several locations, a file in a later location can be overridden by adding a file into an earlier location.

It's easy enough to do: just call getResourceAsStream() on the relevant classloader.  In this case, it could be as simple as:

val parser = javaClass.classLoader.getResourceAsStream("support/certain-file.json")?.use {
    JsonFactory().createParser(it)
}

Here javaClass.classLoader gets the current class's ClassLoader.  (You could use the system one instead, of course.)

use() takes care of closing the resulting InputStream once it's been read.

And luckily, there's a createParser() method which accepts the InputStream.

(Disclaimer: I don't know anything about Kubernetes, or about running Kotlin/Java programs on Windows.  But the beauty of using the classloader is that you don't need to!  If it can load classes, it can load resources too.)

gidds
  • 16,558
  • 2
  • 19
  • 26