Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/amazon-s3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala调用处理程序导致ClassCastException_Scala_Reflection_Proxy_Proxy Pattern - Fatal编程技术网

Scala调用处理程序导致ClassCastException

Scala调用处理程序导致ClassCastException,scala,reflection,proxy,proxy-pattern,Scala,Reflection,Proxy,Proxy Pattern,我正在尝试实现一个代理模式,以便在必要时可以在封面下动态交换底层实例,并使用扩展方法触发交换。我以前在Java中实现过,但在Scala中遇到了问题 这是我的设想: class Client { ...library code... } trait DynamicClient extends Client { def swap: Client } class Provider extends Provider[DynamicClient] { def get():DynamicCli

我正在尝试实现一个代理模式,以便在必要时可以在封面下动态交换底层实例,并使用扩展方法触发交换。我以前在Java中实现过,但在Scala中遇到了问题

这是我的设想:

class Client { ...library code... }

trait DynamicClient extends Client {
   def swap: Client
}

class Provider extends Provider[DynamicClient] {
  def get():DynamicClient {
    java.lang.reflect.Proxy.newProxyInstance(
      classOf[DynamicClient].getClassLoader,
      Array(classOf[DynamicClient]),
      handler)
    .asInstanceOf[DynamicClient]
  }
}

class DynamicClientHandler extends java.lang.reflect.InvocationHandler {

  var client:Client = createNewClient()
  def swap(): {
    client = createNewClient()
    client
  }
  def createNewClient():Client: { ... }


  def invoke(proxy: AnyRef, method: java.lang.reflect.Method, args: Array[AnyRef]): AnyRef = {
      method.getDeclaringClass match {
        case dyn if dyn == classOf[DynamicClient] => swap()
        case _ => method.invoke(client, args: _*)
      }
  }
}
现在的问题是:当我从DynamicClient或代理对象上的对象调用方法时,它们工作得很好

val dynamicClient = injector.instanceOf[DynamicClient]
val initial = dynamicClient.client
val client = dynamicClient.swap()
val dynamicClient.toString // "Client@1234" (Object impl of toString via client instance)
assert(client != initial) //passes just fine, the underlying client is re-initialized
对属于客户机类的方法的任何调用在到达调用处理程序之前都会失败

//Both of the following scenarios fail independently of the other
//ERROR:
dynamicClient.asInstanceOf[Client]
//ERROR:
dynamicClient.doSomeClientMethod()
对于此异常跟踪:

java.lang.ClassCastException: com.sun.proxy.$Proxy22 cannot be cast to Client

为什么我会得到这个cast异常?与Java方式相比,Scala是否有更好的方式来处理代理调用处理?

Ok。我试图让你的例子真正具有可复制性,现在是:

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

class Client

trait DynamicClient extends Client {
  def swap: Client
}

def mkClient =
  Proxy.newProxyInstance(
    classOf[Client].getClassLoader,
    Array(classOf[DynamicClient]),
    new DynamicClientHandler
  ).asInstanceOf[DynamicClient]


class DynamicClientHandler extends java.lang.reflect.InvocationHandler {
  val client = new Client{}

  def invoke(proxy: AnyRef, method: Method, args: Array[AnyRef]): AnyRef =
    if (method.getDeclaringClass == classOf[DynamicClient])
      swap
    else method.invoke(client, args: _*)


  def swap = createNewClient

  def createNewClient = mkClient
}

mkClient.swap
只要您在
客户机
的定义中将
更改为
特征
,此示例就会生效

为什么??因为从
trait
扩展
class
确实是一个限制,它只在scala编译器中工作。因此,从java的角度来看,
接口动态客户端
仍然与
类客户端
没有任何共同之处,正如反射错误所说的那样


因此,您不能真正创建
类的
代理
,应该考虑一些解决方法。

好的。我试图让你的例子真正具有可复制性,现在是:

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

class Client

trait DynamicClient extends Client {
  def swap: Client
}

def mkClient =
  Proxy.newProxyInstance(
    classOf[Client].getClassLoader,
    Array(classOf[DynamicClient]),
    new DynamicClientHandler
  ).asInstanceOf[DynamicClient]


class DynamicClientHandler extends java.lang.reflect.InvocationHandler {
  val client = new Client{}

  def invoke(proxy: AnyRef, method: Method, args: Array[AnyRef]): AnyRef =
    if (method.getDeclaringClass == classOf[DynamicClient])
      swap
    else method.invoke(client, args: _*)


  def swap = createNewClient

  def createNewClient = mkClient
}

mkClient.swap
只要您在
客户机
的定义中将
更改为
特征
,此示例就会生效

为什么??因为从
trait
扩展
class
确实是一个限制,它只在scala编译器中工作。因此,从java的角度来看,
接口动态客户端
仍然与
类客户端
没有任何共同之处,正如反射错误所说的那样


因此,您不能真正创建
类的
代理
,应该考虑一些解决方法。

我认为您的代码包含一些错误,
特征
s,我相信,不能
扩展
esI相信您是错的,但这肯定可能是问题所在。我只是想知道为什么我认为你的代码有一些不准确的地方,
trait
s,我认为,不能
extend
class
esI相信你错了,但这肯定是问题所在。我只是想知道为什么