【问题标题】:How to invoke with reflection a Java function which has method reference as parameters [duplicate]如何通过反射调用具有方法引用作为参数的Java函数[重复]
【发布时间】:2017-10-27 19:01:59
【问题描述】:

一个类(来自 Elasticsearch Rest API)有一个我想要调用的受保护方法。问题是这个方法有方法引用参数

protected <Req extends ActionRequest, Resp> Resp performRequestAndParseEntity(
            Req request,
            CheckedFunction<Req, Request, IOException> requestConverter,
            CheckedFunction<XContentParser, Resp, IOException> entityParser,
            Set<Integer> ignores, Header... headers) throws IOException {
    return performRequest(request, requestConverter, (response) ->
        parseEntity(response.getEntity(), entityParser), ignores, headers);
}

在 API 中,这个方法是这样调用的:

DeleteIndexResponse deleteIndexResponse = restHighLevelClient.performRequestAndParseEntity(
    deleteIndexRequest,
    Request::deleteIndex,
    DeleteIndexResponse::fromXContent,
    Collections.emptySet(),
    headers
);

Java 告诉我“此表达式的目标类型必须是函数接口”用于DeleteIndexRequest::deleteIndexDeleteIndexResponse::fromXContent

我的(不工作)解决方案:

java.lang.Class clazz = restHighLevelClient.getClass();
java.lang.reflect.Method performRequestAndParseEntity = clazz.getDeclaredMethod(
    "performRequestAndParseEntity",
    Object.class,
    org.elasticsearch.common.CheckedFunction.class,
    org.elasticsearch.common.CheckedFunction.class,
    java.util.Set.class,
    org.apache.http.Header.class
);
performRequestAndParseEntity.setAccessible(true);

org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse 
deleteIndexResponse = (org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse)
    performRequestAndParseEntity.invoke(
        restHighLevelClient,
        deleteByIndexRequest,
        org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest::deleteIndex,
        org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse::fromXContent,
        java.util.Collections.emptySet(),
        null
    )
;

编辑

我还尝试将deleteIndex(和fromXContent)转换为CheckedFunction,即调用invoke

performRequestAndParseEntity.invoke(
    ...,
   ((org.elasticsearch.common.CheckedFunction) org.elasticsearch.client.Request::deleteIndex),
    ...
);

我还尝试在invoke 调用之外定义一个变量:

org.elasticsearch.common.CheckedFunction deleteIndexFunction =
    org.elasticsearch.client.Request::deleteIndex;

还有:

org.elasticsearch.common.CheckedFunction deleteIndexFunction =
    (org.elasticsearch.common.CheckedFunction) org.elasticsearch.client.Request::deleteIndex;

总而言之,Java 告诉我们:“类型 Request 没有定义适用于此的 deleteIndex(Object)”,fromXContent 也是如此

有关信息,deleteIndex 是这样定义的:

static Request deleteIndex(DeleteIndexRequest deleteIndexRequest) {
    ...
}

CheckedFunction 是:

@FunctionalInterface
public interface CheckedFunction<T, R, E extends Exception> {
    R apply(T t) throws E;
}

编辑 2
我还尝试对 CheckedFunction 对象进行参数化,结果相似(“类型请求未定义适用于此处的 deleteIndex(DeleteIndexRequest)”):

org.elasticsearch.common.CheckedFunction<org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest, org.elasticsearch.client.Request, Exception> deleteIndexFunction =
        (org.elasticsearch.common.CheckedFunction<org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest, org.elasticsearch.client.Request, Exception>) org.elasticsearch.client.Request::deleteIndex;

我认为问题在于deleteIndex 函数未公开。

【问题讨论】:

    标签: java elasticsearch methods reflection reference


    【解决方案1】:

    Method.invoke 的签名将所有参数声明为Object,无论实际参数类型是什么。这意味着 Object 是编译器试图将您的方法引用转换为实现的类型,因为 Object 不是函数式接口,所以它无法工作。

    要解决这个问题,请将每个方法引用转换为它实际应该是的类型 - org.elasticsearch.common.CheckedFunction。编译器会将其作为方法引用的预期类型,使其能够工作。

    【讨论】:

    • 感谢您的回答。我用这些测试编辑了我的问题。在我最后一次尝试(定义外部变量)中,invoke 似乎还可以,但变量定义失败并显示“类型请求未定义适用于此处的 deleteIndex(Object)”
    猜你喜欢
    • 2012-04-16
    • 1970-01-01
    • 1970-01-01
    • 2020-12-09
    • 2016-05-26
    • 2016-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多