PlayFramework2 Scala File Map - scala

I'm just starting with Scala and have run into a problem that has me stumped, but I'm guessing that I'm missing something easy.
I was following instructions to use the Clapper ClassFinder:
http://thoughts.inphina.com/2011/09/15/building-a-plugin-based-architecture-in-scala/
val classpath = List("./plugins").map(new File(_))
val finder = ClassFinder(classpath)
val classes = finder.getClasses
val classMap = ClassFinder.classInfoMap(classes)
After executing the first line, I see that classpath is set simply to
List(.\plugins)
I'm running this on windows, so the swapping of the slash seems to be OK.
But I expected to see a list of File objects, although I am not sure about this Scala syntax, and perhaps I'm missing something in the Scala IDE. The value for classes shows an "empty iterator".
It seems not to be finding any files in the path that I specified. I tried using an absolute path, but I had the same results. I have a single jar file in the plugins directory that I'm hoping it will find. The plugins directory is at the root of the Play2 project I'm using.
Edit ---
I did find that when I explicitly list the path to one jar that it is able to find it:
val classpath = List("./plugins/myPlugin.jar").map(new File(_))
But I want to find all jar files in the directory.
The following didn't work:
val classpath = List("./plugins/*").map(new File(_))
Nor did this:
val classpath = List("./plugins/*.jar").map(new File(_))

Judging by this issue on the ClassFinder repo on Github it may be a bug.
I think you need to create an explicit list of jar files or to list the ones contained in your folder like:
val classpath =(new File("./plugins")).listFiles.filter(_.getName.endsWith(".jar"))
EDIT: from a cursory glance at ClassFinder's source on GitHub I think it's not a bug. ClassFinder searches for .class files either in jars or in zip files or directly in folders but it looks like it does not mix these things recursively (i.e. if you give it a folder it will look for classes directly in the folder but it won't look for classes in jars in the folder)

if you objective is to list all jar files, you can use following code:
val classpath = List("./plugins").map(path => Option(new File(path).listFiles).getOrElse(Array.empty[java.io.File]) filter(file => file.isFile && file.getName.endsWith(".jar"))).flatten

Related

Get relative path from inside a scala library (while developing that library)

I'm currently developing a scala library and wanted to get a file that is inside it, event when compiled as a Jar dependency. The problem is that when executed from another project where the library is imported, the path is relative to that project. Here is the code to get the file :
private val pathToDocker: Path = Paths.get("src", "main", "resources", "docker-compose")
What can I do to look for my file inside the imported dependency ?
The file won't be in a file system -- it'll be in the compiled JAR.
You can get a JAR resource using a class loader. Here's an example of how to do that in another codebase.
Utility function:
https://github.com/hail-is/hail/blob/6db198ae06/hail/src/main/scala/is/hail/utils/package.scala#L468
Usage to load version info:
https://github.com/hail-is/hail/blob/6db198ae06/hail/src/main/scala/is/hail/package.scala#L21
There is a JarUtil - from an answer of access-file-in-jar-file translate to Scala:
import java.util.jar.JarFile
val jar = new JarFile("path_to_jar/shapeless_2.12-2.3.3.jar")
val entry = jar.getEntry("shapeless/Annotation.class")
val inStream = jar.getInputStream(entry)
As you mentioned scala.io.Source.fromResource works only within your project:
Source.fromResource("tstdir/source.txt")
Make sure the file is in the resources directory, like:
The way I found to achieve getting the path inside a jar depedency was creating a singleton (scala object) that has a method that loads the files. Since it is inside the Jar, the resulting path is relative to the jar itself. Here is the code :
object ClassLoaderTest {
def dockerFile: File =
new File(getClass.getClassLoader.getResource("docker/docker-compose.yml").getPath)
}
When called from a Trait (or an interface), the resulting path is :
jar:file:/home/myname/.ivy2/cache/com.mypackage/libraryname/jars/libraryname.libraryversion.jar!/docker/docker-compose.yml

Unable to use a class from a package in /lib directory

I did a simple thing: I put a jar file I've made myself into /lib directory of a Play application. However, it doesn't work:
def index = Action {
val a = new com.mypackage.Class123 // error! not found Class123
Ok(views.html.index("hello"))
}
It already said sbt, compile, gen-idea but everything is still the same.
By the way, the file /lib/mypackage.jar is 38Mb for some reason.
Try reload in sbt. This is needed to rescan the build file; it might also be needed to rescan the lib directory (I'm not sure).

scala :How to read file in jar

I have directory structure like this
src
main
resources
text.txt
scala
hello
world.scala
test
same as main folder
pom.xml
When in IDE (Intellij10), I could access it with relative path ("src/main/resource/text.txt") but it seems I can not do that when I compile in jar. How to read that file ?
also, I found that test.txt is copy into root of jar. Is this normal behavior ? Since I fear this will be clash with other resources file in src/test/resources.
thanks
From http://www.java-forums.org/advanced-java/5356-text-image-files-within-jar-files.html -
Once the file is inside the jar, you cannot access it with standard FileReader streams since it is treated as a resource. You will need to use Class.getResourceAsStream().
The test.txt being copied into the root is not normal behavior and is probably a setting with your IDE.
8 years later, I am also facing the same question. To ease the life of future developers, here is the answer:
Being copied into the root is normal behaviour, as:
the resources folder is like a src folder and so the content is
copied, not the folder itself.
Now concerning the how-to question:
import scala.io.Source
val name = "text.txt"
val source: Source = Source.fromInputStream(getClass.getClassLoader.getResourceAsStream(name))
// Add the new line character as a separator as by getLines removes it
val resourceAsString: String = source.getLines.mkString("\n")
// Don't forget to close
source.close

Changing sbt project's directory layout

According to sbt tutorial on changing paths I'm trying to change "target" output directory to "someother"
override def outputDirectoryName = "someother"
Everything goes fine except one: sbt automatically creates target directory with ".history" file inside. Why sbt does this when it supposed do create only "someother" dir ? I tryied to override all methods that are inherited from BasicProjectPaths (I use sbt.DefaultProject as superclass of my project descriptor)
override def mainCompilePath = ...
override def testCompilePath = ...
...
But sbt creates "target" folder in spite of paths overriding.
It certainly seems that it should use the overridden outputDirectoryName in trunk...
/** The path to the file that provides persistence for history. */
def historyPath: Option[Path] = Some(outputRootPath / ".history")
def outputPath = crossPath(outputRootPath)
def outputRootPath: Path = outputDirectoryName
def outputDirectoryName = DefaultOutputDirectoryName
(from SBT's current trunk).
It may have been different in a previous version. Have you considered raising a new bug?
In sbt 0.13.5, I found a way to change the target folder by just re-assigning target in the build.sbt file:
target := file("someotherParent") / "someotherSubdir"
This only modifies the directory for the built classes and artifacts, however, the .history file is always in the project root directory.
Unfortunately, some other plugins (xsbt-web-plugin) seem to have problems with that - running the webapp via SBT console produced weird errors, when I switched back to the standard directory layout, these problems disappeared.
A better way to achieve my goals (of all JARS in one directory, whose names contains the JAVA-VM-version) seems to be to specify an appropriate target for publishing - there are less restrictions on "sbt publish", and other plugins are not disturbed by a different directory layout.

How to create a compiler Action for SBT

I want to create an Action to automate GCJ compilation. Since I couldn't make it work with Ant, I decided to try SBT. The docs say how to create an Action and how to run an external process. What I don't yet see is how to reuse the directory tree traversal which exists for java and scala compiler Actions. In this case my input files would be all the .class files under a certain root folder. I would also need to specify a specific classpath for GCJ. Any pointers for this would be appreciated too.
I haven't used GCJ much at all and I'm still pretty new at SBT, but this is how I believe you could write a quick task to do exactly what you are looking for with SBT 0.7.1. You can use a PathFinder to grab all of the class files like so:
val allClasses = (outputPath ##) ** "*.class"
Using that PathFinder and the "compileClasspath" top level method, you can construct a task like this which will run gcj using the current project's classpath and compose all of the .class files into one gcjFile:
val gcj = "/usr/local/bin/gcj"
val gcjFile = "target/my_executable.o"
val allClasses = (outputPath ##) ** "*.class"
lazy val gcjCompile = execTask {
<x>{gcj} --classpath={compileClasspath.get.map(_.absolutePath).mkString(":")} -c {allClasses.get.map(_.absolutePath).mkString("-c ")} -o {gcjFile}</x>
} dependsOn(compile) describedAs("Create a GCJ executable object")