Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

implemented DynamicProxy as portrayed by the Scala reflection team

  • Loading branch information...
commit 53a0e803f03fe715c214c01c03f82baa19d7f2c2 1 parent 020043c
Jan Christopher Vogt cvogt authored
67 src/library/scala/reflect/DynamicProxy.scala
... ... @@ -0,0 +1,67 @@
  1 +package scala.reflect
  2 +/**
  3 + * A dynamic proxy which redirect method calls and attribute access to a given
  4 + * target object at runtime using reflection.
  5 + * A usage example can be found in test/files/run/dynamic-reflect.scala
  6 + * Not supported (yet):
  7 + * - implicit conversions and parameters
  8 + * - multiple arguments lists
  9 + * - explicit type arguments
  10 + */
  11 +trait DynamicProxy extends Dynamic{
  12 + val dynamicProxyTarget : AnyRef
  13 +
  14 + import scala.reflect.mirror._
  15 + /**
  16 + * boxing to preserve information on primitive types for overloading resolution
  17 + */
  18 + case class DynamicReflectBoxed( class_ : Class[_], value: Any )
  19 + object DynamicReflectBoxed{
  20 + implicit def box[@specialized T]( v:T ) = DynamicReflectBoxed( v.getClass, v )
  21 + }
  22 +
  23 + def selectDynamic( method:String ) = {
  24 + val symbol = classToType( dynamicProxyTarget.getClass ).member( newTermName(method).encodedName )
  25 + invoke( dynamicProxyTarget, symbol )()
  26 + }
  27 +
  28 + def updateDynamic( method:String )( value : Any ) = {
  29 + val symbol = classToType( dynamicProxyTarget.getClass ).member( newTermName(method+"_=").encodedName )
  30 + invoke( dynamicProxyTarget, symbol )( value )
  31 + }
  32 +
  33 + def applyDynamic( method:String )( args:DynamicReflectBoxed* ) : Any
  34 + = applyDynamicNamed( method )( args.map( value => ("",value) ) :_* )
  35 +
  36 + def applyDynamicNamed( method:String )( args:(String,DynamicReflectBoxed)* ) : Any = {
  37 + val class_ = dynamicProxyTarget.getClass
  38 + var i = 0
  39 + val toolbox = mkToolBox(mkConsoleReporter(),"")
  40 + val symbol = classToType( dynamicProxyTarget.getClass ).member( newTermName(method).encodedName )
  41 + if(args.size == 0){
  42 + invoke( dynamicProxyTarget, symbol )()
  43 + } else {
  44 + val call =
  45 + Apply(
  46 + Select(
  47 + TypeApply(
  48 + Select(
  49 + Select(
  50 + Ident(newFreeTerm("__this", symbolForName("scala.reflect.DynamicProxy").asType, this, null))
  51 + , newTermName("dynamicProxyTarget")
  52 + ),
  53 + newTermName("asInstanceOf") )
  54 + , List(TypeTree().setType(classToType(class_)))
  55 + )
  56 + ,newTermName(method).encodedName
  57 + )
  58 + ,args.map{ case(name,box) =>
  59 + val value = Ident(newFreeTerm("__arg"+({i+=1;i}.toString), classToType(box.class_), box.value, null))
  60 + if( name == "" ) value
  61 + else AssignOrNamedArg( Ident(name), value )
  62 + }.toList
  63 + )
  64 + toolbox.runExpr( call )
  65 + }
  66 + }
  67 +}
4 src/library/scala/reflect/api/Names.scala
@@ -34,12 +34,12 @@ trait Names {
34 34 def toTypeName: TypeName
35 35
36 36 /** Replaces all occurrences of $op_names in this name by corresponding operator symbols.
37   - * Example: `foo_+=` becomes `foo_$plus$eq`.
  37 + * Example: `foo_$plus$eq` becomes `foo_+=`
38 38 */
39 39 def decoded: String
40 40
41 41 /** Replaces all occurrences of operator symbols in this name by corresponding $op_names.
42   - * Example: `foo_$plus$eq` becomes `foo_+=`
  42 + * Example: `foo_+=` becomes `foo_$plus$eq`.
43 43 */
44 44 def encoded: String
45 45
20 test/files/run/dynamic-proxy.check
... ... @@ -0,0 +1,20 @@
  1 +noargs
  2 +noargs
  3 +nullary
  4 +value
  5 +symbolic
  6 +symbolic with args
  7 +non-existent method
  8 +before mutation
  9 +mutation 1
  10 +after mutation 1
  11 +mutation 2
  12 +after mutation 2
  13 +overloaded with object
  14 +overloaded with primitive
  15 +overloaded with object in var
  16 +overloaded with object in var 2
  17 +typeArgs: I am a car
  18 +default: 4
  19 +default: 3
  20 +named: 6
1  test/files/run/dynamic-proxy.flags
... ... @@ -0,0 +1 @@
  1 +-Xexperimental
72 test/files/run/dynamic-proxy.scala
... ... @@ -0,0 +1,72 @@
  1 +import scala.reflect._
  2 +
  3 +class Car{ override def toString = "I am a car" }
  4 +object x{
  5 + def nullary = "nullary"
  6 + def noargs() = "noargs"
  7 + def - = "symbolic"
  8 + def $(s:String) = "symbolic with args"
  9 + val value = "value"
  10 + def overloaded(i:Int) = "overloaded with primitive"
  11 + def overloaded(s:String) = s
  12 + def default( a:Int, b:Int = 2 ) = "default: "+(a+b)
  13 + def named( a:Int, b:Int, c:Int ) = "named: "+(a+b+c)
  14 + def typeArgs[T]( v:T ) = "typeArgs: "+v
  15 + var mutable = "before mutation"
  16 + def multiArgLists( a:String )( b:String ) = "multiArgList " + a + b
  17 + def bar( s:String )(implicit car:Car) = s + car.toString
  18 +}
  19 +
  20 +object Test extends App{
  21 + val d = new DynamicProxy{ val dynamicProxyTarget = x }
  22 +
  23 + println( d.noargs )
  24 + println( d.noargs() )
  25 + println( d.nullary )
  26 + println( d.value )
  27 + println( d.- )
  28 + println( d.$("x") )
  29 +
  30 + try{
  31 + println( d.test )
  32 + } catch {
  33 + case _ => println("non-existent method")
  34 + }
  35 +
  36 + println( d.mutable )
  37 +
  38 + println("mutation 1")
  39 + d.mutable_=("after mutation 1")
  40 + println( d.mutable )
  41 +
  42 + println("mutation 2")
  43 + d.mutable = "after mutation 2"
  44 + println( d.mutable )
  45 +
  46 + println( d.overloaded("overloaded with object") )
  47 + println( d.overloaded(1) )
  48 +
  49 + // test some non-constant arguments
  50 + def s = "overloaded with object in var"
  51 + println( d.overloaded(s) )
  52 + println( d.overloaded(s + " 2") )
  53 +
  54 + val car = new Car
  55 + println( d.typeArgs(car) ) // inferred
  56 + // println( d.typeArgs[Car](car) ) // explicit not working (yet)
  57 +
  58 + println( d.default( 1,3 ) )
  59 + println( d.default( 1 ) )
  60 +
  61 + println( d.named(1,c=3,b=2) ) // applyDynamicNamed seems to be broken
  62 +
  63 + // println( d.multiArgLists("a")("b") ) // not working yet
  64 +
  65 + /*
  66 + // may never work
  67 + // testing implicit parameters (first test works when moving x into TestDynamicReflect)
  68 + implicit val car2 = new Car
  69 + println( d.bar( "Yeah, ") ); // FAILS: could not find implicit value for parameter car
  70 + {println( d.bar( "Yeah, ") )} // FAILS: could not find implicit value for parameter car
  71 + */
  72 +}

0 comments on commit 53a0e80

Please sign in to comment.
Something went wrong with that request. Please try again.