You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Scala中重写Elasticsearch 2.4.x的FilterClient#doExecute()

解决Elasticsearch 2.4.x下Scala重写FilterClient.doExecute的编译错误

Hey,我碰到过类似Scala与Java泛型交互的坑,尤其是在Elasticsearch 2.x这种老版本里!让我帮你理清楚问题出在哪,以及怎么解决。

问题回顾

你现在卡在Elasticsearch 2.4.x版本(依赖org.elasticsearch % "elasticsearch" % "2.4.x"),没法升级——毕竟后续版本里ActionRequest的泛型参数被移除了,虽然新版本的写法能正常运行,但暂时没法动版本对吧?

你要重写的Java父类方法是这样的:

protected <Request extends ActionRequest, Response extends ActionResponse, RequestBuilder extends ActionRequestBuilder<Request, Response, RequestBuilder>> 
void doExecute(Action<Request, Response, RequestBuilder> action, Request request, ActionListener<Response> listener) { 
    in().execute(action, request, listener); 
}

然后你写了Scala版本的重写代码,结果在Scala 2.11.11、2.11.12、2.12.4里都编译失败:

import org.elasticsearch.action._
import org.elasticsearch.client.{Client, FilterClient}

class DemoFilterClient(underlyingClient: Client) extends FilterClient(underlyingClient) {
 override def doExecute[
 Request <: ActionRequest[_], Response <: ActionResponse, RequestBuilder <: ActionRequestBuilder[Request, Response, RequestBuilder]
 ](
 action: Action[Request, Response, RequestBuilder], request: Request, listener: ActionListener[Response]
 ) = super.doExecute(action, request, listener)
}

编译错误信息看起来挺吓人的:

[info] Compiling 1 Scala source to /home/roberto/development/elasticsearch-scala-client-test/target/scala-2.11/classes ...
[error] /home/roberto/development/elasticsearch-scala-client-test/src/main/scala/com/gu/DemoFilterClient.scala:7:101: type arguments [Request,Response,RequestBuilder] do not conform to class ActionRequestBuilder's type parameter bounds [Request <: org.elasticsearch.action.ActionRequest[_ <: org.elasticsearch.action.ActionRequest[_ <: org.elasticsearch.action.ActionRequest[_ <: AnyRef]]],Response <: org.elasticsearch.action.ActionResponse,RequestBuilder <: org.elasticsearch.action.ActionRequestBuilder[Request,Response,RequestBuilder]]
[error] override def doExecute[Request <: ActionRequest[_], Response <: ActionResponse, RequestBuilder <: ActionRequestBuilder[Request, Response, RequestBuilder]](action: Action[Request, Response, RequestBuilder], request: Request, listener: ActionListener[Response]) = super.doExecute(action, request, listener)
[error] ^
[error] one error found

说白了就是:Scala把Java的泛型边界给过度解析了,尤其是Request的类型被展开成了多层递归的通配符,导致你的泛型约束匹配不上。

解决方法

问题的核心是Scala与Java泛型对递归边界的处理方式不同,我们需要调整Scala代码里的泛型约束,让类型检查器能正确匹配Java的定义。

方案一:用通配符替代ActionRequestBuilder的第一个参数

修改后的代码如下:

import org.elasticsearch.action._
import org.elasticsearch.client.{Client, FilterClient}

class DemoFilterClient(underlyingClient: Client) extends FilterClient(underlyingClient) {
  override def doExecute[
    Request <: ActionRequest[_], 
    Response <: ActionResponse, 
    RequestBuilder <: ActionRequestBuilder[_, Response, RequestBuilder]
 ](
    action: Action[Request, Response, RequestBuilder], 
    request: Request, 
    listener: ActionListener[Response]
  ): Unit = super.doExecute(action, request, listener)
}

方案二:明确Request的边界为ActionRequest[_ <: AnyRef]

如果你想要更贴近Java的泛型声明,也可以这样写:

import org.elasticsearch.action._
import org.elasticsearch.client.{Client, FilterClient}

class DemoFilterClient(underlyingClient: Client) extends FilterClient(underlyingClient) {
  override def doExecute[
    Request <: ActionRequest[_ <: AnyRef], 
    Response <: ActionResponse, 
    RequestBuilder <: ActionRequestBuilder[Request, Response, RequestBuilder]
 ](
    action: Action[Request, Response, RequestBuilder], 
    request: Request, 
    listener: ActionListener[Response]
  ): Unit = super.doExecute(action, request, listener)
}

为什么这两种方法能行?

  • 方案一里,我们把ActionRequestBuilder[Request, Response, RequestBuilder]改成了ActionRequestBuilder[_, Response, RequestBuilder],用通配符_来兼容Scala过度解析的递归边界,让类型检查器不再纠结Request的多层嵌套约束。
  • 方案二则是明确了Request的边界是ActionRequest[_ <: AnyRef],直接匹配错误信息里最内层的_ <: AnyRef约束,避免Scala展开成多层递归。
  • 另外,显式指定返回类型: Unit也是个好习惯,虽然Scala能自动推断,但在重写Java方法时,显式声明能避免一些隐式类型转换的问题。

内容的提问来源于stack exchange,提问作者Roberto Tyley

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:42:45