jeudi 7 septembre 2023

WrongMethodTypeException with MethodHandle.invokeExact() but no arguments and return type is same

I'm using Java 17 on AWS Lambda. I have an interface Foo with a method bar(), returning a CompletableFuture<Map<Bar, Long>>:

public interface Foo {
  public CompletableFuture<Map<Bar, Long>> bar();
}

In the MyProcessor class, I have an instance reference to an implemention of Foo which is FooImpl:

class MyProcessor {

  private final Foo foo;

  MyProcessor() {
    foo = goGetFooImpl();
  }

  void doSomething() {
    …
  }

}

Finally in MyProcessor.doSomething(), I look up the Foo.bar() method and try to invoke it using a method handle (leaving out exception handling for clarity):

  //filter out the only method with the name "bar"
  Method barMethod = foo.getClass().getDeclaredMethods().…;
  MethodHandle = MethodHandles.lookup().unreflect(barMethod);
  CompletableFuture<?> result = (CompletableFuture<?>)methodHandle.invokeExact(foo);

The error message is odd:

java.lang.invoke.WrongMethodTypeException: expected (FooImpl)CompletableFuture but found (Foo)CompletableFuture

I realize with MethodHandle.invokeExact() that the arguments and return type must be exact. In this case there are no arguments. And it is my understanding that the generic type of CompletableFuture is erased at runtime; thus in this case the concrete return type is the same. So what is the problem?

What does the error message mean when it mentions (Fooimpl) and (Foo)? How does the type of the target impact the type of CompletableFuture?

I realize that the bar() method is declared on Foo, but looked up that method on the class of an instance of FooImpl. But why would that be a problem? From the documentation I had understood that MethodHandle.invokeExact() works on virtual methods.

I can call methodHandle.invoke(foo) here and it works fine, but not methodHandle.invokeExact(foo). What is not "exact" about what I'm doing? Does anyone know what the error message means?

I found MethodHandle cast return type which appears to be related, but I'm still not getting it. A CompletableFuture is a CompletableFuture. Since when is there such things as (Foo)CompletableFuture and (FooImpl)CompletableFuture and why would they be different?





Aucun commentaire:

Enregistrer un commentaire