More API docs for the classpath module

This commit is contained in:
Mark Harrah 2013-08-16 14:21:45 -04:00
parent 50232c56af
commit 78178f8716
5 changed files with 59 additions and 2 deletions

View File

@ -5,7 +5,10 @@ package sbt
object ModuleUtilities
{
def getObject(className: String, loader: ClassLoader) =
/** Reflectively loads and returns the companion object for top-level class `className` from `loader`.
* The class name should not include the `$` that scalac appends to the underlying jvm class for
* a companion object. */
def getObject(className: String, loader: ClassLoader): AnyRef =
{
val obj = Class.forName(className + "$", true, loader)
val singletonField = obj.getField("MODULE$")

View File

@ -7,7 +7,8 @@ import scala.collection._
object ReflectUtilities
{
def transformCamelCase(name: String, separator: Char) =
/** Converts the camelCase String `name` to lowercase separated by `separator`. */
def transformCamelCase(name: String, separator: Char): String =
{
val buffer = new StringBuilder
for(char <- name)
@ -33,6 +34,9 @@ object ReflectUtilities
flatMap(_.getDeclaredFields).
map(f => (f.getName, f)):_*)
/** Collects all `val`s of type `T` defined on value `self`.
* The returned Map maps the name of each `val` to its value.
* This depends on scalac implementation details to determine what is a `val` using only Java reflection. */
def allValsC[T](self: AnyRef, clazz: Class[T]): immutable.SortedMap[String, T] =
{
var mappings = new immutable.TreeMap[String, T]
@ -51,7 +55,14 @@ object ReflectUtilities
}
mappings
}
/** Collects all `val`s of type `T` defined on value `self`.
* The returned Map maps the name of each `val` to its value.
* This requires an available `Manifest` for `T` and depends on scalac implementation details to determine
* what is a `val` using only Java reflection. */
def allVals[T](self: AnyRef)(implicit mt: scala.reflect.Manifest[T]): immutable.SortedMap[String, T] =
allValsC(self, mt.runtimeClass).asInstanceOf[immutable.SortedMap[String,T]]
}
/** An exception to indicate that while traversing the `val`s for an instance of `className`, the `val` named `valName` was `null`. */
final class UninitializedVal(val valName: String, val className: String) extends RuntimeException("val " + valName + " in class " + className + " was null.\nThis is probably an initialization problem and a 'lazy val' should be used.")

View File

@ -105,6 +105,8 @@ final class FilteredLoader(parent: ClassLoader, filter: ClassFilter) extends Cla
throw new ClassNotFoundException(className)
}
}
/** Defines a filter on class names. */
trait ClassFilter
{
def include(className: String): Boolean
@ -114,18 +116,31 @@ abstract class PackageFilter(packages: Iterable[String]) extends ClassFilter
require(packages.forall(_.endsWith(".")))
protected final def matches(className: String): Boolean = packages.exists(className.startsWith)
}
/** Excludes class names that begin with one of the packages in `exclude`.
* Each package name in `packages` must end with a `.` */
final class ExcludePackagesFilter(exclude: Iterable[String]) extends PackageFilter(exclude)
{
def include(className: String): Boolean = !matches(className)
}
/** Includes class names that begin with one of the packages in `include`.
* Each package name in `include` must end with a `.` */
final class IncludePackagesFilter(include: Iterable[String]) extends PackageFilter(include)
{
def include(className: String): Boolean = matches(className)
}
/** Configures a [[NativeCopyLoader]].
* The loader will provide native libraries listed in `explicitLibraries` and on `searchPaths` by copying them to `tempDirectory`.
* If `tempDirectory` is unique to the class loader, this ensures that the class loader gets a unique path for
* the native library and avoids the restriction on a native library being loaded by a single class loader. */
final class NativeCopyConfig(val tempDirectory: File, val explicitLibraries: Seq[File], val searchPaths: Seq[File])
/** Loads native libraries from a temporary location in order to work around the jvm native library uniqueness restriction.
* See [[NativeCopyConfig]] for configuration details. */
trait NativeCopyLoader extends ClassLoader
{
/** Configures this loader. See [[NativeCopyConfig]] for details. */
protected val config: NativeCopyConfig
import config._

View File

@ -7,6 +7,7 @@ package classpath
import java.net.URL
import java.util.Enumeration
/** A class loader that always fails to load classes and resources. */
final class NullLoader extends ClassLoader
{
override final def loadClass(className: String, resolve: Boolean): Class[_] = throw new ClassNotFoundException("No classes can be loaded from the null loader")
@ -14,7 +15,20 @@ final class NullLoader extends ClassLoader
override def getResources(name: String): Enumeration[URL] = null
}
/** Exception thrown when `loaderA` and `loaderB` load a different Class for the same name. */
class DifferentLoaders(message: String, val loaderA: ClassLoader, val loaderB: ClassLoader) extends ClassNotFoundException(message)
/** A ClassLoader with two parents `parentA` and `parentB`. The predicates direct lookups towards one parent or the other.
*
* If `aOnlyClasses` returns `true` for a class name, class lookup delegates to `parentA` only.
* Otherwise, if `bOnlyClasses` returns `true` for a class name, class lookup delegates to `parentB` only.
* If both `aOnlyClasses` and `bOnlyClasses` are `false` for a given class name, both class loaders must load the same Class or
* a [[DifferentLoaders]] exception is thrown.
*
* If `aOnlyResources` is `true` for a resource path, lookup delegates to `parentA` only.
* Otherwise, if `bOnlyResources` is `true` for a resource path, lookup delegates to `parentB` only.
* If neither are `true` for a resource path and either `parentA` or `parentB` return a valid URL, that valid URL is returned.
**/
class DualLoader(parentA: ClassLoader, aOnlyClasses: String => Boolean, aOnlyResources: String => Boolean,
parentB: ClassLoader, bOnlyClasses: String => Boolean, bOnlyResources: String => Boolean) extends ClassLoader(new NullLoader)
{
@ -76,6 +90,7 @@ class DualLoader(parentA: ClassLoader, aOnlyClasses: String => Boolean, aOnlyRes
}
}
/** Concatenates `a` and `b` into a single `Enumeration`.*/
final class DualEnumeration[T](a: Enumeration[T], b: Enumeration[T]) extends Enumeration[T]
{
// invariant: current.hasMoreElements or current eq b

View File

@ -10,10 +10,17 @@ package classpath
object RawURL
{
/** Constructs a URL with scheme `raw` and path `file` that will return the bytes for `value` in the platform default encoding
* when a connection to the URL is opened. */
def apply(file: String, value: String): URL =
apply(file, value.getBytes)
/** Constructs a URL with scheme `raw` and path `file` that will return the bytes `value` when a connection to the URL is opened. */
def apply(file: String, value: Array[Byte]): URL =
apply(file)(new ByteArrayInputStream(value))
/** Constructs a URL with scheme `raw` and path `file` that will use `value` to construct the `InputStream` used when a connection
* to the URL is opened. */
def apply(file: String)(value: => InputStream): URL =
new URL("raw", null, -1, file, new RawStreamHandler(value))
@ -31,14 +38,20 @@ object RawURL
}
}
/** A ClassLoader that looks up resource requests in a `Map` prior to the base ClassLoader's resource lookups. */
trait RawResources extends FixedResources
{
/** The map from resource paths to the raw String content to provide via the URL returned by [[findResource]] or [[findResources]]. */
protected def resources: Map[String, String]
override protected final val resourceURL = resources.transform(RawURL.apply)
}
/** A ClassLoader that looks up resource requests in a `Map` prior to the base ClassLoader's resource lookups. */
trait FixedResources extends ClassLoader
{
/** The map from resource paths to URL to provide in [[findResource]] and [[findResources]]. */
protected def resourceURL: Map[String, URL]
override def findResource(s: String): URL = resourceURL.getOrElse(s, super.findResource(s))
import java.util.Collections.{enumeration, singletonList}