All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.twitter.util.reflect.Proxy.scala Maven / Gradle / Ivy

package com.twitter.util.reflect

import java.io.Serializable
import java.lang.reflect.Method

import net.sf.cglib.proxy.{MethodInterceptor => CGMethodInterceptor, _}

import com.twitter.util.Future

class NonexistentTargetException extends Exception("MethodCall was invoked without a valid target.")

object Proxy {
  def apply[I <: AnyRef : Manifest](f: MethodCall[I] => AnyRef) = {
    new ProxyFactory[I](f).apply()
  }

  def apply[I <: AnyRef : Manifest](target: I, f: MethodCall[I] => AnyRef) = {
    new ProxyFactory[I](f).apply(target)
  }
}

object ProxyFactory {
  private[reflect] object NoOpInterceptor extends MethodInterceptor[AnyRef](None, m => null)

  private[reflect] object IgnoredMethodFilter extends CallbackFilter {
    def accept(m: Method) = {
      m.getName match {
        case "hashCode" => 1
        case "equals"   => 1
        case "toString" => 1
        case _          => 0
      }
    }
  }
}

class AbstractProxyFactory[I <: AnyRef : Manifest] {
  import ProxyFactory._

  final val interface = implicitly[Manifest[I]].runtimeClass

  protected final val proto = {
    val e = new Enhancer
    e.setCallbackFilter(IgnoredMethodFilter)
    e.setCallbacks(Array(NoOpInterceptor, NoOp.INSTANCE))
    e.setSuperclass(interface)
    e.create.asInstanceOf[Factory]
  }

  protected final def newWithCallback(f: MethodCall[I] => AnyRef) = {
    proto.newInstance(Array(new MethodInterceptor(None, f), NoOp.INSTANCE)).asInstanceOf[I]
  }

  protected final def newWithCallback[T <: I](target: T, f: MethodCall[I] => AnyRef) = {
    proto.newInstance(Array(new MethodInterceptor(Some(target), f), NoOp.INSTANCE)).asInstanceOf[I]
  }
}

class ProxyFactory[I <: AnyRef : Manifest](f: MethodCall[I] => AnyRef) extends AbstractProxyFactory[I] {
  def apply[T <: I](target: T) = newWithCallback(target, f)
  def apply()                  = newWithCallback(f)
}

private[reflect] class MethodInterceptor[I <: AnyRef](target: Option[I], callback: MethodCall[I] => AnyRef)
extends CGMethodInterceptor with Serializable {
  val targetRef = target.getOrElse(null).asInstanceOf[I]

  final def intercept(p: AnyRef, m: Method, args: Array[AnyRef], methodProxy: MethodProxy) = {
    callback(new MethodCall(targetRef, m, args, methodProxy))
  }
}

final class MethodCall[T <: AnyRef] private[reflect] (
  targetRef: T,
  val method: Method,
  val args: Array[AnyRef],
  methodProxy: MethodProxy)
extends (() => AnyRef) {

  lazy val target = if (targetRef ne null) Some(targetRef) else None

  def clazz          = method.getDeclaringClass
  def clazzName      = clazz.getName
  def className      = clazzName
  def parameterTypes = method.getParameterTypes
  def name           = method.getName
  def returnsUnit    = {
    val rt = method.getReturnType
    (rt eq classOf[Unit]) || (rt eq classOf[Null]) || (rt eq java.lang.Void.TYPE)
  }
  def returnsFuture  = classOf[Future[_]] isAssignableFrom method.getReturnType

  private def getTarget = if (targetRef ne null) targetRef else throw new NonexistentTargetException

  def apply() = methodProxy.invoke(getTarget, args)

  def apply(newTarget: T) = methodProxy.invoke(newTarget, args)
  def apply(newArgs: Array[AnyRef]) = methodProxy.invoke(getTarget, newArgs)
  def apply(newTarget: T, newArgs: Array[AnyRef]) = methodProxy.invoke(newTarget, newArgs)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy