Scala 2.10 comes with a great reflection API. There are two entry points to it, however: runtime universe and macro context universe.
When using runtime reflection, you should import scala.reflect.runtime.universe. When using reflection inside a macro implementation, you should import universe from the context.
Is it possible to write some code that works in both environments? How should one obtain the universe?
Consider this example:
class MyReflection(val u: scala.reflect.api.Universe) {
import u._
def foo[T: TypeTag] = implicitly[TypeTag[T]].tpe.members // returns MyReflection.u.MemberScope
}
val x = new MyReflection(scala.reflect.runtime.universe)
val members: scala.reflect.runtime.universe.MemberScope = x.foo[String] // BANG! Compiler error
This won't compile because of type mismatch. Same time, it is obvious that both scala.reflect.runtime.universe.MemberScope and MyReflection.u.MemberScope in this example share the same API. Is there a way to abstract over different universes?
Or am I possibly doing something philosophically wrong with trying to export reflection artifacts (MemberScope in this example)?
You can just accept the universe as a parameter:
class MyReflection(val u: scala.reflect.api.Universe) {
import u._
def foo[T : TypeTag] = implicitly[TypeTag[T]].tpe.members
}
val x = new MyReflection(scala.reflect.runtime.universe)
Note that you'll have to refer to the universe via your instance of MyReflection to get the path-dependent types right.
val members: x.u.MemberScope = x.foo[String]
Have a look at this question for more examples and options.
Related
Considering the following code:
import scala.reflect.api.Universe
object UnqualifiedTypeTag {
val RuntimeUniverse = scala.reflect.runtime.universe
trait HasUniverse {
val universe: Universe with Singleton
def uType: RuntimeUniverse.TypeTag[universe.type] = implicitly
}
object HasRuntime extends HasUniverse {
override val universe: RuntimeUniverse.type = RuntimeUniverse
}
def main(args: Array[String]): Unit = {
println(HasRuntime.uType)
}
}
Ideally, this part of the program should yield TypeTag[HasRuntime.universe.type], or at least fail its compilation, due to implicitly only able to see universe.type, which is not known at call site. (in contrast, WeakTypeTag[universe.type] should totally work)
Surprisingly, the above program yields TypeTag[HasUniverse.this.universe.type]. This apparently breaks many contracts, namely:
TypeTag cannot be initialised from abstract types, unlike WeakTypeTag
TypeTag can always be erased to a Class
What's the purpose of this design, and what contract does TypeTag provide? In addition, is this the reason why ClassTag was supposed to be superseded after Scala 2.11, but instead was kept as-is until now?
Context
I use scala 2.11.6 currently, possibly 2.11.7 in the future.
Given compiled class files in the classpath, I want to do 2 things:
Find the name of any objects that implements a certain interface:
trait Service
trait ServiceFactory {
def create(): Service
}
...
package my.package
object MyServiceFactory extends ServiceFactory {
def create(): Service = new Service()
}
Here the name would be something like my.package.MyServiceFactory as it implements the ServiceFactory trait.
Given the fully qualified name of the object I want to get the reference to the object's instance.
val factory = getInstance[ServiceFactory]("my.package.MyServiceFactory")
val service = factory.create()
Problem
The problem to both scenarios is verifying the type inheritance and making sure it is a singleton object.
Checking the class seems straight-forward but given all the documentation
I could understand, none helped me implementing something like isSingletonObject(name: String): Boolean as used in:
import scala.reflect.runtime.{universe => ru}
val rm = ru.runtimeMirror(classLoader)
def getInstance[T](name: String)(implicit tt: ru.TypeTag[T]): T = {
if (!isSingletonObject(name)) throw new RuntimeException(
s"$name does not specify a singleton object")
val moduleSym = try rm.staticModule(name).asModule
if (!(moduleSym.moduleClass.asClass.selfType <:< tt.tpe))
throw new RuntimeException("Type of loaded module " + moduleSym.fullName
+ " does not satisfy subtype relationship with "
+ tt.tpe.typeSymbol.fullName)
val mm = rm.reflectModule(moduleSym.asModule)
mm.instance.asInstanceOf[T]
}
How can one find objects and verify that a given name is really an object?
Alternative approaches to the given scenarios are also welcome.
For the first question, you could use ClassUtil library. Note that it'll find Java classes, and the ones which correspond to objects will have names ending in $class. See also Scala Reflection - Loading or finding classes based on trait.
For the second, objects are called "modules" in Scala reflection, so you don't need isSingletonObject(name); if it isn't, rm.staticModule(name).asModule in your code will fail. There doesn't seem to be a way to check if it's a compiler-generated empty companion object (isSynthetic returns false), but they will be ruled out by the subtyping check anyway (so will the static parts of Java classes, but you can also filter those out using isJava).
In Java, while type arguments are erased in runtime, it is possible to find the actual type arguments passed to a superclass:
class Derived extends Base<String> {
// ...
}
ParameterizedType type = (ParameterizedType)Derived.class.getGenericSuperclass();
Type[] args = type.getActualTypeArguments(); // gives {String.class}
While I can use the same Java reflection to Scala class, It does not catch Scala's value types:
class Base[T]
class Derived extends Base[Int]
classOf[Derived]
.getGenericSuperclass
.asInstanceOf[ParameterizedType]
.getActualTypeArguments // gives {Object.class}, not {int.class}
Is it possible to determine the value type used when extending from a generic superclass? I am loading classes from a jar file so it'd be best to achieve this only using a java.lang.Class instance.
In Java reflection you won't be able to obtain Int and other AnyVal types because they are handled specially by the compiler and if they are used generically, they will be represented by Object. However, you can use Scala reflection, and it is wholly possible to go from Java reflection to Scala reflection. Here's how:
import scala.reflect.runtime.universe._
class Base[T]
class Derived extends Base[Int]
object Main extends App {
val rm = runtimeMirror(getClass.getClassLoader) // whatever class loader you're using
val derivedSym = rm.staticClass(classOf[Derived].getName)
val baseSym = rm.staticClass(classOf[Base[_]].getName)
val TypeRef(_, _, params) = derivedSym.typeSignature.baseType(baseSym)
println(s"$derivedSym extends $baseSym[${params.mkString(", ")}]")
}
Unfortunately, unless you know exactly what you are searching for, you will have hard time finding proper documentation. I have found the answer on scala-users mailing list. Scala reflection is still experimental and, AFAIK, it will probably be superseded by a better one in future Scala versions.
In scala, I want to be able to say
val user = Node.create[User](...) // return User object
So here's what I have so far:
def create[T : TypeTag](map: Map[String, Any]) {
val type = typeOf[T]
// create class from type here???
}
I've been digging around how to create classes from generic types and found out that using ClassManifest seems to be deprecated. Instead, type tags are here, so I'm able to do something like this typeOf[T] and actually get the type.. but then I'm lost. If I could get the class, then I could use something like class.newInstance and manually set the fields from there.
Question is: given a type, can I get a class instance of the given type?
The easiest way in fact is to use ClassTag:
def create[T : ClassTag](map: Map[String, Any]): T = {
val clazz: Class[_] = classTag[T].runtimeClass
clazz.newInstance(<constructor arguments here>).asInstanceOf[T]
}
ClassTag is a thin wrapper around Java Class, primarily used for arrays instantiation.
TypeTag facility is more powerful. First, you can use it to invoke Java reflection:
import scala.reflect.runtime.universe._
def create[T: TypeTag](map: Map[String, Any]): T = {
val mirror = runtimeMirror(getClass.getClassLoader) // current class classloader
val clazz: Class[_] = mirror.runtimeClass(typeOf[T].typeSymbol.asClass)
clazz.newInstance(<constructor arguments here>).asInstanceOf[T]
}
However, Scala reflection allows to instantiate classes without dropping back to Java reflection:
def create[T: TypeTag](map: Map[String, Any]): T = {
// obtain type symbol for the class, it is like Class but for Scala types
val typeSym = typeOf[T].typeSymbol.asClass
// obtain class mirror using runtime mirror for the given classloader
val mirror = runtimeMirror(getClass.getClassLoader) // current class classloader
val cm = mirror.reflectClass(typeSym)
// resolve class constructor using class mirror and
// a constructor declaration on the type symbol
val ctor = typeSym.decl(termNames.CONSTRUCTOR).asMethod
val ctorm = cm.reflectConstructor(cm)
// invoke the constructor
ctorm(<constructor arguments here>).asInstanceOf[T]
}
If you want to create a class with overloaded constructors, it may require more work though - you'll have to select correct constructor from declarations list, but the basic idea is the same. You can read more on Scala reflection here
There is a way to do it with reflection: either runtime reflection, or in a macro. Regarding runtime reflection way, you can have a look at my blog post where I tried to do something like what you are trying to do now. Using compile-time reflection with macros might be a better option, depending on your need.
I have a number of use cases for this, all around the idea of interop between existing Java libraries and new Scala Code. The use case I've selected is the easiest I think.
Use Case:
I working on providing a JUnit Runner for some scala tests (so that I can get my lovely red / green bar in Eclipse)
The runner needs to have a constructor with a java class as a parameter. So in Scala I can do the following:
class MyRunner(val clazz: Class[Any]) extends Runner {
def getDescription(): Description
def run(notifier: RunNotifier)
}
When I use either
#RunWith(MyRunner)
object MyTestObject
or
#RunWith(MyRunner)
class MyTestClass
then the runner is indeed instantiated correctly, and is passed a suitable class object
Unfortunately what i want to do now is to "get hold of" the object MyTestObject, or create a MyTestClass, which are both Scala entities. I would prefer to use Scala Reflection, but I also want to use the standard Junit jar.
What I have done
The following Stackover flow questions were educational, but not the same problem. There were the nearest questions I could find
How to create a TypeTag manually?
Any way to obtain a Java class from a Scala (2.10) type tag or symbol?
Using Scala reflection with Java reflection
The discussion on Environments, Universes and Mirrors in http://docs.scala-lang.org/overviews/reflection/environment-universes-mirrors.html was good, and the similar documents on other scala reflection also helped. Mostly through it is about the Scala reflection.
I browsed the Scaladocs, but my knowledge of Scala reflection wasn't enough (yet) to let me get what I wanted out of them.
Edit:
As asked here is the code of the class that is being created by reflection
#RunWith(classOf[MyRunner])
object Hello2 extends App {
println("starting")
val x= "xxx"
}
So the interesting thing is that the solution proposed below using the field called MODULE$ doesn't print anything and the value of x is null
This solution works fine if you want to use plan old java reflection. Not sure if you can use scala reflection given all you will have is a Class[_] to work with:
object ReflectTest {
import collection.JavaConversions._
def main(args: Array[String]) {
val fooObj = instantiate(MyTestObject.getClass())
println(fooObj.foo)
val fooClass = instantiate(classOf[MyTestClass])
println(fooClass.foo)
}
def instantiate(clazz:Class[_]):Foo = {
val rm = ru.runtimeMirror(clazz.getClassLoader())
val declaredFields = clazz.getDeclaredFields().toList
val obj = declaredFields.find(field => field.getName() == "MODULE$") match{
case Some(modField) => modField.get(clazz)
case None => clazz.newInstance()
}
obj.asInstanceOf[Foo]
}
}
trait Foo{
def foo:String
}
object MyTestObject extends Foo{
def foo = "bar"
}
class MyTestClass extends Foo{
def foo = "baz"
}