scala.reflect.api.Mirrors.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of scala-reflect Show documentation
Show all versions of scala-reflect Show documentation
Reflection Library for the Scala Programming Language
/*
* Scala (https://www.scala-lang.org)
*
* Copyright EPFL and Lightbend, Inc.
*
* Licensed under Apache License 2.0
* (http://www.apache.org/licenses/LICENSE-2.0).
*
* See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*/
package scala
package reflect
package api
/**
* EXPERIMENTAL
*
* This trait provides support for Mirrors in the Scala Reflection API.
*
* `Mirror`s are a central part of Scala Reflection. All information provided by
* reflection is made accessible through `Mirror`s. Depending on the type of information
* to be obtained, or the reflective action to be taken, different flavors of mirrors
* must be used. "Classloader" mirrors can be used to obtain representations of types
* and members. From a classloader `Mirror`, it's possible to obtain more specialized
* "invoker" `Mirror`s (the most commonly-used mirrors), which implement reflective
* invocations, such as method/constructor calls and field accesses.
*
* The two flavors of mirrors:
*
*
* - '''“Classloader” mirrors'''. These mirrors translate names to symbols
* (via methods `staticClass`/`staticModule`/`staticPackage`).
* - '''"Invoker” mirrors'''. These mirrors implement reflective invocations
* (via methods `MethodMirror.apply`, `FieldMirror.get`, etc). These "invoker"
* mirrors are the types of mirrors that are most commonly used.
*
*
* === Compile-time Mirrors ===
* Compile-time `Mirror`s make use of only classloader `Mirror`s to load `Symbol`s
* by name.
*
* The entry point to classloader `Mirror`s is via [[scala.reflect.macros.blackbox.Context#mirror]] or [[scala.reflect.macros.whitebox.Context#mirror]].
* Typical methods which use classloader `Mirror`s include [[scala.reflect.api.Mirror#staticClass]],
* [[scala.reflect.api.Mirror#staticModule]], and [[scala.reflect.api.Mirror#staticPackage]]. For
* example:
* {{{
* import scala.reflect.macros.blackbox.Context
*
* case class Location(filename: String, line: Int, column: Int)
*
* object Macros {
* def currentLocation: Location = macro impl
*
* def impl(c: Context): c.Expr[Location] = {
* import c.universe._
* val pos = c.macroApplication.pos
* val clsLocation = c.mirror.staticModule("Location") // get symbol of "Location" object
* c.Expr(Apply(Ident(clsLocation), List(Literal(Constant(pos.source.path)), Literal(Constant(pos.line)), Literal(Constant(pos.column)))))
* }
* }
* }}}
*
* ''Of Note:'' There are several high-level alternatives that one can use to avoid having to manually
* lookup symbols. For example, `typeOf[Location.type].termSymbol` (or `typeOf[Location].typeSymbol`
* if we needed a `ClassSymbol`), which are type safe since we don’t have to use `String`s to lookup
* the `Symbol`.
*
* === Runtime Mirrors ===
*
* Runtime `Mirror`s make use of both classloader and invoker `Mirror`s.
*
* The entry point to `Mirror`s for use at runtime is via `ru.runtimeMirror()`, where
* `ru` is [[scala.reflect.runtime.universe]].
*
* The result of a [[scala.reflect.api.JavaUniverse#runtimeMirror]] call is a classloader mirror,
* of type [[scala.reflect.api.Mirrors#ReflectiveMirror]], which can load symbols by names as
* discussed above (in the “Compile-time” section).
*
* A classloader mirror can create invoker mirrors, which include: [[scala.reflect.api.Mirrors#InstanceMirror]],
* [[scala.reflect.api.Mirrors#MethodMirror]], [[scala.reflect.api.Mirrors#FieldMirror]],
* [[scala.reflect.api.Mirrors#ClassMirror]] and [[scala.reflect.api.Mirrors#ModuleMirror]].
*
* Examples of how these two types of `Mirror`s interact are available below.
*
* === Types of Mirrors, Their Use Cases & Examples ===
*
* '''[[scala.reflect.api.Mirrors#ReflectiveMirror]]'''. Used for loading `Symbol`s by name, and
* as an entry point into invoker mirrors. Entry point: `val m = ru.runtimeMirror()`.
* Example:
* {{{
* scala> val ru = scala.reflect.runtime.universe
* ru: scala.reflect.api.JavaUniverse = ...
*
* scala> val m = ru.runtimeMirror(getClass.getClassLoader)
* m: reflect.runtime.universe.Mirror = JavaMirror ...
* }}}
*
* '''[[scala.reflect.api.Mirrors#InstanceMirror]]'''. Used for creating invoker `Mirror`s for methods
* and fields and for inner classes and inner objects (modules). Entry point: `val im = m.reflect()`.
* Example:
* {{{
* scala> class C { def x = 2 }
* defined class C
*
* scala> val im = m.reflect(new C)
* im: reflect.runtime.universe.InstanceMirror = instance mirror for C@3442299e
* }}}
*
* '''[[scala.reflect.api.Mirrors#MethodMirror]]'''. Used for invoking instance methods (Scala only has
* instance methods-- methods of objects are instance methods of object instances, obtainable
* via `ModuleMirror.instance`). Entry point: `val mm = im.reflectMethod()`.
* Example:
* {{{
* scala> val methodX = typeOf[C].decl(TermName("x")).asMethod
* methodX: reflect.runtime.universe.MethodSymbol = method x
*
* scala> val mm = im.reflectMethod(methodX)
* mm: reflect.runtime.universe.MethodMirror = method mirror for C.x: scala.Int (bound to C@3442299e)
*
* scala> mm()
* res0: Any = 2
* }}}
*
* '''[[scala.reflect.api.Mirrors#FieldMirror]]'''. Used for getting/setting instance fields
* (Scala only has instance fields-- fields of objects are instance methods of object instances
* obtainable via ModuleMirror.instance). Entry point:
* `val fm = im.reflectMethod()`.
* Example:
* {{{
* scala> class C { val x = 2; val y = 3 }
* defined class C
*
* scala> val m = ru.runtimeMirror(getClass.getClassLoader)
* m: reflect.runtime.universe.Mirror = JavaMirror ...
*
* scala> val im = m.reflect(new C)
* im: reflect.runtime.universe.InstanceMirror = instance mirror for C@5f0c8ac1
*
* scala> val fieldX = typeOf[C].decl(TermName("x")).asTerm.accessed.asTerm
* fieldX: reflect.runtime.universe.TermSymbol = value x
* scala> val fmX = im.reflectField(fieldX)
* fmX: reflect.runtime.universe.FieldMirror = field mirror for C.x (bound to C@5f0c8ac1)
*
* scala> fmX.get
* res0: Any = 2
*
* scala> fmX.set(3) // NOTE: can set an underlying value of an immutable field!
*
* scala> val fieldY = typeOf[C].decl(TermName("y")).asTerm.accessed.asTerm
* fieldY: reflect.runtime.universe.TermSymbol = variable y
*
* scala> val fmY = im.reflectField(fieldY)
* fmY: reflect.runtime.universe.FieldMirror = field mirror for C.y (bound to C@5f0c8ac1)
*
* scala> fmY.get
* res1: Any = 3
*
* scala> fmY.set(4)
*
* scala> fmY.get
* res2: Any = 4
* }}}
*
* '''[[scala.reflect.api.Mirrors#ClassMirror]]'''. Used for creating invoker mirrors for constructors.
* Entry points: for ''static classes'' `val cm1 = m.reflectClass()`,
* for ''inner classes'' `val mm2 = im.reflectClass()`.
* Example:
* {{{
* scala> case class C(x: Int)
* defined class C
*
* scala> val m = ru.runtimeMirror(getClass.getClassLoader)
* m: reflect.runtime.universe.Mirror = JavaMirror ...
*
* scala> val classC = typeOf[C].typeSymbol.asClass
*
* classC: reflect.runtime.universe.Symbol = class C
*
* scala> val cm = m.reflectClass(classC)
* cm: reflect.runtime.universe.ClassMirror = class mirror for C (bound to null)
*
* scala> val ctorC = typeOf[C].decl(ru.nme.CONSTRUCTOR).asMethod
* ctorC: reflect.runtime.universe.MethodSymbol = constructor C
*
* scala> val ctorm = cm.reflectConstructor(ctorC)
* ctorm: reflect.runtime.universe.MethodMirror = constructor mirror for C.(x: scala.Int): C (bound to null)
*
* scala> ctorm(2)
* res0: Any = C(2)
* }}}
*
* '''[[scala.reflect.api.Mirrors#ModuleMirror]]'''. Used for getting singleton instances of objects.
* Entry points: for ''static objects (modules)'' `val mm1 = m.reflectModule()`,
* for ''inner objects (modules)'' `val mm2 = im.reflectModule()`.
* Example:
* {{{
* scala> object C { def x = 2 }
* defined module C
*
* scala> val m = ru.runtimeMirror(getClass.getClassLoader)
* m: reflect.runtime.universe.Mirror = JavaMirror ...
*
* scala> val objectC = typeOf[C.type].termSymbol.asModule
* objectC: reflect.runtime.universe.ModuleSymbol = object C
*
* scala> val mm = m.reflectModule(objectC)
* mm: reflect.runtime.universe.ModuleMirror = module mirror for C (bound to null)
*
* scala> val obj = mm.instance
* obj: Any = C$@1005ec04
* }}}
*
* For more information about `Mirrors`s, see the
* [[https://docs.scala-lang.org/overviews/reflection/environment-universes-mirrors.html Reflection Guide: Mirrors]]
*
* @contentDiagram hideNodes "*Api"
* @group ReflectionAPI
*/
trait Mirrors { self: Universe =>
/** The base type of all mirrors of this universe.
*
* This abstract type conforms the base interface for all mirrors defined in [[scala.reflect.api.Mirror]]
* and is gradually refined in specific universes (e.g. `Mirror` of a [[scala.reflect.api.JavaUniverse]] is capable of reflection).
* @group Mirrors
*/
type Mirror >: Null <: scala.reflect.api.Mirror[self.type]
/** The root mirror of this universe. This mirror contains standard Scala classes and types such as `Any`, `AnyRef`, `AnyVal`,
* `Nothing`, `Null`, and all classes loaded from scala-library, which are shared across all mirrors within the enclosing universe.
* @group Mirrors
*/
val rootMirror: Mirror
/** Abstracts the runtime representation of a class on the underlying platform.
* @group Mirrors
*/
type RuntimeClass >: Null <: AnyRef
/** Has no special methods. Is here to provides erased identity for `RuntimeClass`.
* @group API
*/
trait RuntimeClassApi
// todo. an improvement might be having mirrors reproduce the structure of the reflection domain
// e.g. a ClassMirror could also have a list of fields, methods, constructors and so on
// read up more on the proposed design in "Reflecting Scala" by Y. Coppel
/** A mirror that reflects a runtime value.
* See [[scala.reflect.api.package the overview page]] for details on how to use runtime reflection.
* @group Mirrors
*/
trait InstanceMirror {
/** The instance value reflected by this mirror */
def instance: Any
/** The symbol corresponding to the runtime class of the reflected instance */
def symbol: ClassSymbol
/** Reflects against a field symbol and returns a mirror
* that can be used to get and, if appropriate, set the value of the field.
*
* FieldMirrors are the only way to get at private[this] vals and vars and
* might be useful to inspect the data of underlying Java fields.
* For all other uses, it's better to go through the fields accessor.
*
* In particular, there should be no need to ever access a field mirror
* when reflecting on just the public members of a class or trait.
* Note also that only accessor MethodMirrors, but not FieldMirrors will accurately reflect overriding behavior.
*
* To get a field symbol by the name of the field you would like to reflect,
* use `.symbol.info.member(TermName()).asTerm.accessed`.
* For further information about member lookup refer to `Symbol.info`.
*
* The input symbol can be either private or non-private (Scala reflection transparently deals with visibility).
* It must be a member (declared or inherited) of the class of the instance underlying this mirror.
*
* The input symbol can represent either a field itself or one of the corresponding accessors
* (in all cases the resulting mirror will refer to the field symbol).
*
* If a field symbol doesn't correspond to a reflectable entity of the underlying platform,
* a `ScalaReflectionException` exception will be thrown. This might happen, for example, for primary constructor parameters.
* Typically they produce class fields, however, private parameters that aren't used outside the constructor
* remain plain parameters of a constructor method of the class.
*/
def reflectField(field: TermSymbol): FieldMirror
/** Reflects against a method symbol and returns a mirror
* that can be used to invoke the method provided.
*
* To get a method symbol by the name of the method you would like to reflect,
* use `.symbol.info.member(TermName()).asMethod`.
* For further information about member lookup refer to `Symbol.info`.
*
* The input symbol can be either private or non-private (Scala reflection transparently deals with visibility).
* It must be a member (declared or inherited) of the instance underlying this mirror.
*/
def reflectMethod(method: MethodSymbol): MethodMirror
/** Reflects against an inner class symbol and returns a mirror
* that can be used to create instances of the class, inspect its companion object or perform further reflections.
*
* To get a class symbol by the name of the class you would like to reflect,
* use `.symbol.info.member(TypeName()).asClass`.
* For further information about member lookup refer to `Symbol.info`.
*
* The input symbol can be either private or non-private (Scala reflection transparently deals with visibility).
* It must be a member (declared or inherited) of the instance underlying this mirror.
*/
def reflectClass(cls: ClassSymbol): ClassMirror
/** Reflects against an inner module symbol and returns a mirror
* that can be used to get the instance of the object or inspect its companion class.
*
* To get a module symbol by the name of the object you would like to reflect,
* use `.symbol.info.member(TermName()).asModule`.
* For further information about member lookup refer to `Symbol.info`.
*
* The input symbol can be either private or non-private (Scala reflection transparently deals with visibility).
* It must be a member (declared or inherited) of the instance underlying this mirror.
*/
def reflectModule(mod: ModuleSymbol): ModuleMirror
}
/** A mirror that reflects a field.
* See [[scala.reflect.api.package the overview page]] for details on how to use runtime reflection.
* @group Mirrors
*/
trait FieldMirror {
/** The object containing the field */
def receiver: Any
/** The field symbol representing the field.
*
* In Scala `val` and `var` declarations are usually compiled down to a pair of
* a backing field and corresponding accessor/accessors, which means that a single
* declaration might correspond to up to three different symbols. Nevertheless
* the `FieldMirror.symbol` field always points to a backing field symbol.
*/
def symbol: TermSymbol
/** Retrieves the value stored in the field.
*
* Scala reflection uses reflection capabilities of the underlying platform,
* so `FieldMirror.get` might throw platform-specific exceptions associated
* with getting a field or invoking a getter method of the field.
*
* If `symbol` represents a field of a base class with respect to the class of the receiver,
* and this base field is overridden in the class of the receiver, then this method will retrieve
* the value of the base field. To achieve overriding behavior, use reflectMethod on an accessor.
*/
def get: Any
/** Updates the value stored in the field.
*
* If a field is immutable, a `ScalaReflectionException` will be thrown.
*
* Scala reflection uses reflection capabilities of the underlying platform,
* so `FieldMirror.get` might throw platform-specific exceptions associated
* with setting a field or invoking a setter method of the field.
*
* If `symbol` represents a field of a base class with respect to the class of the receiver,
* and this base field is overridden in the class of the receiver, then this method will set
* the value of the base field. To achieve overriding behavior, use reflectMethod on an accessor.
*/
def set(value: Any): Unit
/** Creates a new mirror which uses the same symbol, but is bound to a different receiver.
* This is significantly faster than recreating the mirror from scratch.
*/
def bind(newReceiver: Any): FieldMirror
}
/** A mirror that reflects a method.
* See [[scala.reflect.api.package the overview page]] for details on how to use runtime reflection.
* @group Mirrors
*/
trait MethodMirror {
/** The receiver object of the method */
def receiver: Any
/** The method symbol representing the method */
def symbol: MethodSymbol
/** The result of applying the method to the given arguments
*
* Scala reflection uses reflection capabilities of the underlying platform,
* so `FieldMirror.get` might throw platform-specific exceptions associated
* with invoking the corresponding method or constructor.
*/
def apply(args: Any*): Any
/** Creates a new mirror which uses the same symbol, but is bound to a different receiver.
* This is significantly faster than recreating the mirror from scratch.
*/
def bind(newReceiver: Any): MethodMirror
}
/** A mirror that reflects the instance or static parts of a runtime class.
* See [[scala.reflect.api.package the overview page]] for details on how to use runtime reflection.
* @group Mirrors
*/
trait TemplateMirror {
/** True if the mirror represents the static part
* of a runtime class or the companion object of a Scala class.
* One has:
*
* this.isStatic == this.isInstanceOf[ModuleMirror]
* !this.isStatic == this.isInstanceOf[ClassMirror]
*/
def isStatic: Boolean
/** The Scala symbol corresponding to the reflected runtime class or object */
def symbol: Symbol
}
/** A mirror that reflects a Scala object definition or the static parts of a runtime class.
* See [[scala.reflect.api.package the overview page]] for details on how to use runtime reflection.
* @group Mirrors
*/
trait ModuleMirror extends TemplateMirror {
/** The Scala module symbol corresponding to the reflected object */
override def symbol: ModuleSymbol
/** If the reflected runtime class corresponds to a Scala object definition,
* returns the single instance representing that object.
* If this mirror reflects the static part of a runtime class, returns `null`.
*/
def instance: Any
}
/** A mirror that reflects the instance parts of a runtime class.
* See [[scala.reflect.api.package the overview page]] for details on how to use runtime reflection.
* @group Mirrors
*/
trait ClassMirror extends TemplateMirror {
/** The Scala class symbol corresponding to the reflected class */
override def symbol: ClassSymbol
/** Reflects against a constructor symbol and returns a mirror
* that can be used to invoke it and construct instances of this mirror's symbols.
*
* To get a constructor symbol you would like to reflect,
* use `.symbol.info.member(termNames.CONSTRUCTOR).asMethod`.
* For further information about member lookup refer to `Symbol.info`.
*
* The input symbol can be either private or non-private (Scala reflection transparently deals with visibility).
* It must be a member (declared or inherited) of the class underlying this mirror.
*/
def reflectConstructor(constructor: MethodSymbol): MethodMirror
}
/** A mirror that reflects instances and static classes.
* See [[scala.reflect.api.package the overview page]] for details on how to use runtime reflection.
* @group Mirrors
*/
trait ReflectiveMirror extends scala.reflect.api.Mirror[Mirrors.this.type] {
/** A reflective mirror for the given object.
*
* Such a mirror can be used to further reflect against the members of the object
* to get/set fields, invoke methods and inspect inner classes and objects.
*/
// we need a ClassTag here to preserve boxity of primitives
// the class tag lets us tell apart `mirror.reflect(2)` and `mirror.reflect(new Integer(2))`
def reflect[T: ClassTag](obj: T): InstanceMirror
/** Reflects against a static class symbol and returns a mirror
* that can be used to create instances of the class, inspect its companion object or perform further reflections.
*
* To get a class symbol by the name of the class you would like to reflect,
* use `.classSymbol()`.
*
* The input symbol can be either private or non-private (Scala reflection transparently deals with visibility).
* It must be static, i.e. either top-level or nested within one or several static objects.
*/
def reflectClass(cls: ClassSymbol): ClassMirror
/** Reflects against a static module symbol and returns a mirror
* that can be used to get the instance of the object or inspect its companion class.
*
* To get a module symbol by the name of its companion class you would like to reflect,
* use `.classSymbol().companion.get`.
*
* The input symbol can be either private or non-private (Scala reflection transparently deals with visibility).
* It must be static, i.e. either top-level or nested within one or several static objects.
*/
def reflectModule(mod: ModuleSymbol): ModuleMirror
}
/** The API of a mirror for a reflective universe.
* See [[scala.reflect.api.package the overview page]] for details on how to use runtime reflection.
* @group Mirrors
*/
trait RuntimeMirror extends ReflectiveMirror { self =>
/** Maps a Scala type to the corresponding Java class object */
def runtimeClass(tpe: Type): RuntimeClass
/** Maps a Scala class symbol to the corresponding Java class object
* @throws java.lang.ClassNotFoundException if there is no Java class
* corresponding to the given Scala class symbol.
* Note: If the Scala symbol is ArrayClass, a ClassNotFound exception is thrown
* because there is no unique Java class corresponding to a Scala generic array
*/
def runtimeClass(cls: ClassSymbol): RuntimeClass
/** A class symbol for the specified runtime class.
* @return The class symbol for the runtime class in the current class loader.
* @throws java.lang.ClassNotFoundException if no class with that name exists
* @throws scala.ScalaReflectionException if no corresponding symbol exists
* to do: throws anything else?
*/
def classSymbol(rtcls: RuntimeClass): ClassSymbol
/** A module symbol for the specified runtime class.
* @return The module symbol for the runtime class in the current class loader.
* @throws java.lang.ClassNotFoundException if no class with that name exists
* @throws scala.ScalaReflectionException if no corresponding symbol exists
* to do: throws anything else?
*/
def moduleSymbol(rtcls: RuntimeClass): ModuleSymbol
}
}