Skip to content

Instantly share code, notes, and snippets.

@pierangeloc
Last active January 6, 2019 23:33
Show Gist options
  • Save pierangeloc/f4dc6ba42ff233637fe945e80441ec97 to your computer and use it in GitHub Desktop.
Save pierangeloc/f4dc6ba42ff233637fe945e80441ec97 to your computer and use it in GitHub Desktop.
On resources access from packaged jvm apps
def loadResources(onBehalfOf: Class[_])(path: String): List[Path] = {
    val url: URL = onBehalfOf.getClassLoader.getResource(path)
    if (url.toURI.getScheme.contains("jar")) {
      val jar: URL = onBehalfOf.getProtectionDomain.getCodeSource.getLocation
      val jarFile: Path = Paths.get(jar.toString.substring("file:".length))
      val fs: FileSystem = FileSystems.newFileSystem(jarFile, null)
      val directoryStream: DirectoryStream[Path] = Files.newDirectoryStream(fs.getPath(path))
      directoryStream.asScala.toList
    } else {
      val path: Path = Paths.get(url.toURI)
      val directoryStream: DirectoryStream[Path] = Files.newDirectoryStream(path)
      directoryStream.asScala.toList
    }
  }

This is the only generic way I've found to load, from within a library, resources provided by the wrapping app. E.g. library like Flyway looks for migration scripts in the classpath of the invoker app. It needs to know the physical location of that class, in order to open a file system around it and access the files.

A trivial Java solution would be

final ClassLoader classLoader = getClass().getClassLoader();
final URL resource = classLoader.getResource(dirPath);
final String file = resource.getFile();
final File[] fileArr = new File(file).listFiles((dir, name) -> true);

The only case in which such a solution works, is when dealing with a fat jar, or an exploded, unpackaged application.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment