Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Scala offer a way to "proxy" or "decorate" a function without repeating the argument list?

I have a class with the (admittedly stupid) name Application. There is also a class ApplicationRepository that features a private save(Application) method.

I would like to add a method to ApplicationRepository that creates an Application instance (from exactly the constructor parameters) and saves it. I do not want to expose save or use a parameter of type Application.

def createApplication(firstDay:String, lastDay:String, details:String, substitute:User, projectManager:User) = {
  val a = Application(firstDay, lastDay, details, substitute, projectManager)
  save(a)
}

Basically my question boils down to:

In Scala - can I create a "proxy" function with the same parameter list as a "proxied" function, pass all the arguments without caring about them, and then do different stuff?

like image 817
Klaus Baumgartner Avatar asked Nov 11 '22 16:11

Klaus Baumgartner


1 Answers

2 years later I ran into this situation and I solved my case using java proxies. The actual magic is built in using java's invocation handler () and Proxy ()

Hat Tip to (How to use java proxy in scala) where this answer is based on.

scala> :paste
// Entering paste mode (ctrl-D to finish)

import java.lang.reflect.{Method, InvocationHandler, Proxy}

object ProxyTesting {

  // You need an interface or java's proxy to work.
  trait ProxyTestIface {
    // your function signature here
    def createApplication( firstDay:String, lastDay:String, details:String, substitute:String, projectManager:String):Unit = ???
  }

  // your object implementation
  class ProxyTest extends ProxyTestIface{
    // your function implementation
    override def createApplication( firstDay:String, lastDay:String, details:String, substitute:String, projectManager:String):Unit = {

      println("Actual Function is called")

      Unit
    }
  }

  def test() {
    val obj = new ProxyTest

    val impl = Proxy.newProxyInstance(
      obj.getClass.getClassLoader,
      Array(classOf[ProxyTestIface]),
      new InvocationHandler {
        def invoke(proxy: scala.AnyRef, method: Method, args: Array[AnyRef]): AnyRef = {
          // this shows you can execute prior and post your decorated function.
          println(s"Proxy Funcion is called: ${args.mkString(",")}")
          val res = method.invoke(obj, args:_*)
          println(s"Proxy Funcion is called: 2nd time ${args.mkString(",")}")
          res
        }
      }
    ).asInstanceOf[ProxyTestIface]

    impl.createApplication("firstDayMsg", "lastDayMsg", "detailsMsg", "substituteMsg", "projgMgrMsg")
  }

}

// Exiting paste mode, now interpreting.

import java.lang.reflect.{Method, InvocationHandler, Proxy}
defined object ProxyTesting

scala> ProxyTesting.test()
Proxy Funcion is called: firstDayMsg,lastDayMsg,detailsMsg,substituteMsg,projgMgrMsg
Actual Funcion is called
Proxy Funcion is called: 2nd time firstDayMsg,lastDayMsg,detailsMsg,substituteMsg,projgMgrMsg

scala>
like image 199
critium Avatar answered Nov 14 '22 23:11

critium