Obtenga instancia de objeto compañero con la nueva API de reflexión de Scala
reflection (2)
Dave! Gracias por estar interesado en la nueva reflexión. Los primeros usuarios han impulsado el proceso de desarrollo de la reflexión y las macros en gran medida, y estoy muy feliz de ser parte de nuestra increíble comunidad.
Antes de responder a su pregunta, me gustaría comenzar con un descargo de responsabilidad. En 2.10.0-M4 acabamos de sentar las bases de la API de reflexión de Scala. Todavía está caliente fuera de la prensa, por lo que los documentos son muy escasos y la API no está exactamente plagada de comodidades. Funciona, pero requiere pruebas y comentarios. Claro, jugar con las API previas a la publicación es problemático, pero siempre estoy aquí para ayudarlo.
Hasta ahora tenemos un borrador de lo que en el futuro se convertirá en el SIP de reflexión: https://docs.google.com/document/d/1Z1VhhNPplbUpaZPIYdc0_EUv5RiGQ2X4oqp0i-vz1qw/edit#heading=h.pqwdkl1226tc . Puede leerlo de inmediato o puede leer mi respuesta a continuación.
trait Base {
def companion: MetaBase = {
// runtime reflection is typically done
// by importing things from scala.reflect.runtime package
import scala.reflect.runtime._
// the new Scala reflection API is mirror based
// mirrors constitute a hierarchy of objects
// that closely follows the hierarchy of the things they reflect
// for example, for a class you''ll have a ClassMirror
// for a method you''ll have a MethodMirror and so on
// why go the extra mile?
// because this provides more flexibility than traditional approaches
// you can read more about mirror-based designs here:
// https://dl.dropbox.com/u/10497693/Library/Computer%20Science/Metaprogramming/Reflection/mirrors.pdf
// https://dl.dropbox.com/u/10497693/Library/Computer%20Science/Metaprogramming/Reflection/reflecting-scala.pdf
// bottom line is that to do anything you will need a mirror
// for example, in your case, you need a ClassMirror
// remember I said that mirrors provide more flexibility?
// for one, this means that mirror-based reflection facilities
// might have multiple implementations
// in a paper linked above, Gilad Bracha muses over a runtime
// that loads things remotely over the network
// in our case we might have different mirrors for JVM and CLR
// well, anyways
// the canonical (and the only one now) implementation of the mirror API
// is Java-based reflection that uses out of the box classloaders
// here''s its root: https://github.com/scalamacros/kepler/blob/9f71e9f114c10b52350c6c4ec757159f06e55daa/src/reflect/scala/reflect/api/Mirrors.scala#L178
// yeah, right, I''ve just linked a source file from trunk
// we''ll have Scaladocs for that soon, but for now take a look
// this file is interfaces-only and is heavy on comments
// to start with Java-based reflection implementation you need a classloader
// let''s grab one and instantiate the root mirror
// btw, the same effect could be achieved by writing
// `scala.reflect.runtime.currentMirror`
val rootMirror = universe.runtimeMirror(getClass.getClassLoader)
// now when we''ve finally entered the reflective world
// we can get the stuff done
// first we obtain a ClassSymbol that corresponds to the current instance
// (ClassSymbols are to Scala the same as Classes are to Java)
var classSymbol = rootMirror.classSymbol(getClass)
// having a Scala reflection entity
// we can obtain its reflection using the rootMirror
val classMirror = rootMirror.reflectClass(classSymbol)
// now we just traverse the conceptual hierarchy of mirrors
// that closely follows the hierarchy of Scala reflection concepts
// for example, a ClassMirror has a companion ModuleMirror and vice versa
val moduleMirror = classMirror.companion.get
// finally, we''ve arrived at our destination
moduleMirror.instance.asInstanceOf[MetaBase]
}
}
trait MetaBase {
// stuff
}
// ---
class Foo extends Base
object Foo extends MetaBase
object Test extends App {
assert(new Foo().companion == Foo)
}
Actualizar. Vea también la excelente publicación de Daniel Sobral: http://dcsobral.blogspot.ch/2012/07/json-serialization-with-reflection-in.html .
Con la nueva API de reflexión de Scala, ¿es posible obtener una referencia al objeto complementario de una clase? Estoy pensando algo así:
trait Base {
def companion: MetaBase = someReflectionMagic(this).asInstanceOf[MetaBase]
}
trait MetaBase {
// stuff
}
// ---
class Foo extends Base
object Foo extends MetaBase
assert(new Foo.companion == Foo)
No vi el último comentario de Eugene y se me ocurrió esto. Funciona para scala 2.10.
trait ReflectionSugars{
import scala.reflect.runtime.{universe => ru}
private lazy val universeMirror = ru.runtimeMirror(getClass.getClassLoader)
def companionOf[T](implicit tt: ru.TypeTag[T]) = {
val companionMirror = universeMirror.reflectModule(ru.typeOf[T].typeSymbol.companionSymbol.asModule)
companionMirror.instance
}
}
trait X extends ReflectionSugars{
def companion = companionOf[X]
}
https://gist.github.com/piotrga/5928581
¡Espero que esto ayude!