如何使用反射调用具有方法引用作为参数的Java函数

时间:2017-10-27 19:02:00

标签: java elasticsearch methods reflection reference

一个类(来自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告诉我&#34; 此表达式的目标类型必须是功能界面&#34; 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告诉我们:&#34; 类型Request没有定义适用于此处的deleteIndex(Object)&#34;,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对象进行参数化(&#34;类型Request没有定义适用于此处的deleteIndex(DeleteIndexRequest)&#34; ):

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功能不公开。

1 个答案:

答案 0 :(得分:0)

Method.invoke的签名将所有参数声明为Object,而不管实际的参数类型是什么。这意味着Object是编译器尝试将方法引用转换为实现的类型,由于Object不是函数接口,因此无法工作。

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