summaryrefslogtreecommitdiff
path: root/src/library/scala/reflect/DynamicProxy.scala
blob: 3ed17fea417cb5b9843caaa185b20dbd2aca66db (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package scala.reflect
/**
 * A dynamic proxy which redirects method calls and attribute access to a given
 * target object at runtime using reflection.
 *
 * Usage example:
 *
 *  object x{ def hello = "hello world" }
 *  val d = new DynamicProxy{ val dynamicProxyTarget = x }
 *  assert( d.hello == "hello world" )
 *
 * Not supported (yet):
 *   - implicit conversions and parameters
 *   - multiple arguments lists
 *   - explicit type arguments
 */
trait DynamicProxy extends Dynamic{
  /** Method calls on DynamicProxy are redirected to this object. Needs to be defined in a subclass. */
  val dynamicProxyTarget : AnyRef

  import scala.reflect.mirror._
  /**
   * boxing to preserve information on primitive types for overloading resolution
   */
  case class DynamicReflectBoxed( class_ : Class[_], value: Any )
  object DynamicReflectBoxed{
    implicit def box[@specialized T]( v:T ) = DynamicReflectBoxed( v.getClass, v )
  }

  def selectDynamic( method:String ) = {
    val symbol = classToType( dynamicProxyTarget.getClass ).member( newTermName(method).encodedName )
    invoke( dynamicProxyTarget, symbol )()
  }

  def updateDynamic( method:String )( value : Any ) = {
    val symbol = classToType( dynamicProxyTarget.getClass ).member( newTermName(method+"_=").encodedName )
    invoke( dynamicProxyTarget, symbol )( value )
  }

  def applyDynamic( method:String )( args:DynamicReflectBoxed* ) : Any
    = applyDynamicNamed( method )( args.map( value => ("",value) ) :_* )

  def applyDynamicNamed( method:String )( args:(String,DynamicReflectBoxed)* ) : Any = {
    val class_ = dynamicProxyTarget.getClass
    var i = 0
    val toolbox = mkToolBox(mkConsoleFrontEnd(),"")
    val symbol = classToType( dynamicProxyTarget.getClass ).member( newTermName(method).encodedName )
    if(args.size == 0){
      invoke( dynamicProxyTarget, symbol )()
    } else {
      val call =
        Apply(
          Select(
            TypeApply(
              Select(
                Select(
                  Ident(newFreeTerm("__this", symbolForName("scala.reflect.DynamicProxy").asType, this))
                  , newTermName("dynamicProxyTarget")
                ),
                newTermName("asInstanceOf") )
              , List(TypeTree().setType(classToType(class_)))
            )
            ,newTermName(method).encodedName
          )
          ,args.map{ case(name,box) =>
            val value = Ident(newFreeTerm("__arg"+({i+=1;i}.toString), classToType(box.class_), box.value))
            if( name == "" ) value
            else AssignOrNamedArg( Ident(name), value )
          }.toList
        )
      toolbox.runExpr( call )
    }
  }
}