Issue
I want to use the Apache POI library in a Scala project.
How can I convert a scala.io.BufferedSource
type to a java.io.File
type?
val file = Source.fromResource("resource.file") // is type scala.io.BufferedSource
// how can I do the conversion here
val workbook = WorkbookFactory.create(file) // requires type java.io.File
This works, but I want to avoid specifying the folder path since the folder structure is handled by sbt convention:
val file = new File("src/main/resources/resource.file")
val workbook = WorkbookFactory.create(file)
Thank you for your time 🙏
Solution
Note that the folder structure is not handled by sbt
.
What happens is that the contents of src/main/resources
are shipped into the JAR and are available in your classpath as a resource.
If you do something along the lines of what Source.fromResource
does, you should be able to get what you need.
Here is the code snippet for reference:
/** Reads data from a classpath resource, using either a context classloader (default) or a passed one.
*
* @param resource name of the resource to load from the classpath
* @param classLoader classloader to be used, or context classloader if not specified
* @return the buffered source
*/
def fromResource(resource: String, classLoader: ClassLoader = Thread.currentThread().getContextClassLoader())(implicit codec: Codec): BufferedSource =
Option(classLoader.getResourceAsStream(resource)) match {
case Some(in) => fromInputStream(in)
case None => throw new FileNotFoundException(s"resource '$resource' was not found in the classpath from the given classloader.")
}
This code is found on GitHub and here is the link for a recent HEAD
: https://github.com/scala/scala/blob/8a2cf63ee5bad8c8c054f76464de0e10226516a0/src/library/scala/io/Source.scala#L174-L184
In principle, you can load the resource as a stream using the Java API and pass it to the WorkbookFactory.create
static method overload that takes an InputStream
as an input that someone mentioned in a comment.
Something along the lines of
def maybeResourceAt(path: String): Option[InputStream] =
Option(
Thread.
currentThread().
getContextClassLoader().
getResourceAsStream(path)
)
val input = maybeResourceAt("resource.file").getOrElse(sys.error("oh noes"))
val workbook = WorkbookFactory.create(input)
should get the job done.
I'm not sure who's in charge of closing the InputStream
. Intuitively I would say that create
should consume it entirely but double check with the library's documentation to be sure.
Answered By - stefanobaghino