diff options
author | Som Snytt <som.snytt@gmail.com> | 2014-10-04 12:33:11 -0700 |
---|---|---|
committer | Som Snytt <som.snytt@gmail.com> | 2014-10-06 08:00:22 -0700 |
commit | 964a197cd90e561d05c9d725cc13895f18b6a6d0 (patch) | |
tree | 51a80e3c486ad12b6b4f97920c696bdf167d54b4 /src/reflect | |
parent | 7b2c3cb8bb0f5f96f3182f551eb82cb1c59d460c (diff) | |
download | scala-964a197cd90e561d05c9d725cc13895f18b6a6d0.tar.gz scala-964a197cd90e561d05c9d725cc13895f18b6a6d0.tar.bz2 scala-964a197cd90e561d05c9d725cc13895f18b6a6d0.zip |
SI-8843 AbsFileCL acts like a CL
Let the AbstractFileClassLoader override just the usual suspects.
Normal delegation behavior should ensue.
That's instead of overriding `getResourceAsStream`, which was intended
that "The repl classloader now works more like you'd expect a classloader to."
(Workaround for "Don't know how to construct an URL for something which exists
only in memory.")
Also override `findResources` so that `getResources` does the obvious thing,
namely, return one iff `getResource` does.
The translating class loader for REPL only special-cases `foo.class`: as
a fallback, take `foo` as `$line42.$read$something$foo` and try that class file.
That's the use case for "works like you'd expect it to."
There was a previous fix to ensure `getResource` doesn't take a class name.
The convenience behavior, that `classBytes` takes either a class name or a resource
path ending in ".class", has been promoted to `ScalaClassLoader`.
Diffstat (limited to 'src/reflect')
-rw-r--r-- | src/reflect/scala/reflect/internal/util/AbstractFileClassLoader.scala | 66 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/util/ScalaClassLoader.scala | 6 |
2 files changed, 31 insertions, 41 deletions
diff --git a/src/reflect/scala/reflect/internal/util/AbstractFileClassLoader.scala b/src/reflect/scala/reflect/internal/util/AbstractFileClassLoader.scala index 10a8b4c812..30dcbc21ca 100644 --- a/src/reflect/scala/reflect/internal/util/AbstractFileClassLoader.scala +++ b/src/reflect/scala/reflect/internal/util/AbstractFileClassLoader.scala @@ -5,16 +5,16 @@ package scala package reflect.internal.util -import scala.reflect.io.AbstractFile +import scala.collection.{ mutable, immutable } +import scala.reflect.io.{ AbstractFile, Streamable } +import java.net.{ URL, URLConnection, URLStreamHandler } import java.security.cert.Certificate import java.security.{ ProtectionDomain, CodeSource } -import java.net.{ URL, URLConnection, URLStreamHandler } -import scala.collection.{ mutable, immutable } +import java.util.{ Collections => JCollections, Enumeration => JEnumeration } -/** - * A class loader that loads files from a {@link scala.tools.nsc.io.AbstractFile}. +/** A class loader that loads files from a {@link scala.tools.nsc.io.AbstractFile}. * - * @author Lex Spoon + * @author Lex Spoon */ class AbstractFileClassLoader(val root: AbstractFile, parent: ClassLoader) extends ClassLoader(parent) @@ -22,7 +22,7 @@ class AbstractFileClassLoader(val root: AbstractFile, parent: ClassLoader) { protected def classNameToPath(name: String): String = if (name endsWith ".class") name - else name.replace('.', '/') + ".class" + else s"${name.replace('.', '/')}.class" protected def findAbstractFile(name: String): AbstractFile = { var file: AbstractFile = root @@ -56,35 +56,25 @@ class AbstractFileClassLoader(val root: AbstractFile, parent: ClassLoader) file } - // parent delegation in JCL uses getResource; so either add parent.getResAsStream - // or implement findResource, which we do here as a study in scarlet (my complexion - // after looking at CLs and URLs) - override def findResource(name: String): URL = findAbstractFile(name) match { + override protected def findClass(name: String): Class[_] = { + val bytes = classBytes(name) + if (bytes.length == 0) + throw new ClassNotFoundException(name) + else + defineClass(name, bytes, 0, bytes.length, protectionDomain) + } + override protected def findResource(name: String): URL = findAbstractFile(name) match { case null => null - case file => new URL(null, "repldir:" + file.path, new URLStreamHandler { + case file => new URL(null, s"memory:${file.path}", new URLStreamHandler { override def openConnection(url: URL): URLConnection = new URLConnection(url) { - override def connect() { } + override def connect() = () override def getInputStream = file.input } }) } - - // this inverts delegation order: super.getResAsStr calls parent.getRes if we fail - override def getResourceAsStream(name: String) = findAbstractFile(name) match { - case null => super.getResourceAsStream(name) - case file => file.input - } - // ScalaClassLoader.classBytes uses getResAsStream, so we'll try again before delegating - override def classBytes(name: String): Array[Byte] = findAbstractFile(classNameToPath(name)) match { - case null => super.classBytes(name) - case file => file.toByteArray - } - override def findClass(name: String): Class[_] = { - val bytes = classBytes(name) - if (bytes.length == 0) - throw new ClassNotFoundException(name) - else - defineClass(name, bytes, 0, bytes.length, protectionDomain) + override protected def findResources(name: String): JEnumeration[URL] = findResource(name) match { + case null => JCollections.enumeration(JCollections.emptyList[URL]) //JCollections.emptyEnumeration[URL] + case url => JCollections.enumeration(JCollections.singleton(url)) } lazy val protectionDomain = { @@ -106,15 +96,13 @@ class AbstractFileClassLoader(val root: AbstractFile, parent: ClassLoader) throw new UnsupportedOperationException() } - override def getPackage(name: String): Package = { - findAbstractDir(name) match { - case null => super.getPackage(name) - case file => packages.getOrElseUpdate(name, { - val ctor = classOf[Package].getDeclaredConstructor(classOf[String], classOf[String], classOf[String], classOf[String], classOf[String], classOf[String], classOf[String], classOf[URL], classOf[ClassLoader]) - ctor.setAccessible(true) - ctor.newInstance(name, null, null, null, null, null, null, null, this) - }) - } + override def getPackage(name: String): Package = findAbstractDir(name) match { + case null => super.getPackage(name) + case file => packages.getOrElseUpdate(name, { + val ctor = classOf[Package].getDeclaredConstructor(classOf[String], classOf[String], classOf[String], classOf[String], classOf[String], classOf[String], classOf[String], classOf[URL], classOf[ClassLoader]) + ctor.setAccessible(true) + ctor.newInstance(name, null, null, null, null, null, null, null, this) + }) } override def getPackages(): Array[Package] = diff --git a/src/reflect/scala/reflect/internal/util/ScalaClassLoader.scala b/src/reflect/scala/reflect/internal/util/ScalaClassLoader.scala index 63ea6e2c49..41011f6c6b 100644 --- a/src/reflect/scala/reflect/internal/util/ScalaClassLoader.scala +++ b/src/reflect/scala/reflect/internal/util/ScalaClassLoader.scala @@ -53,8 +53,10 @@ trait ScalaClassLoader extends JClassLoader { } /** An InputStream representing the given class name, or null if not found. */ - def classAsStream(className: String) = - getResourceAsStream(className.replaceAll("""\.""", "/") + ".class") + def classAsStream(className: String) = getResourceAsStream { + if (className endsWith ".class") className + else s"${className.replace('.', '/')}.class" // classNameToPath + } /** Run the main method of a class to be loaded by this classloader */ def run(objectName: String, arguments: Seq[String]) { |