0

When I try to use something like this

class Example {
    ...

    private Future<String> asyncMethod() {
        ...
        return somePromise;
    }

    private static void callback(Future<String> future) {
        System.out.println(future.getNow());
    }

    public static void main(String[] args) {
        asyncMethod().addListener(Example::callback);
    }
}

I get an error

Example.java:[17,34] incompatible types: invalid method reference
   incompatible types: io.netty.util.concurrent.Future<capture#1 of ? super java.lang.String>
   cannot be converted to io.netty.util.concurrent.Future<java.lang.String>

There are no errors with an anonymous class as the listener

asyncMethod().addListener(new GenericFutureListener<Future<String>>() {
    @Override
    public void operationComplete(Future<String> future) throws Exception {
        System.out.println(future.getNow());
    }
});

But it's ugly and verbose :( What can I do to solve this problem in the most elegant way?

Hivemaster
  • 139
  • 10

2 Answers2

1

You can cast method reference

asyncMethod().addListener((GenericFutureListener<Future<String>>) Example::callback);

It's less verbose but still not perfect. To improve this solution a little you can move long type definition to the functional interface

class Example {
    @FunctionalInterface
    private interface Callback extends GenericFutureListener<Future<String>> {
        void operationComplete(Future<String> future) throws Exception;
    }

    private static void callback(Future<String> future) {
        System.out.println(future.getNow());
    }

    public static void main(String[] args) {
        asyncMethod().addListener((Callback) Example::callback);
    }
}

Or you can wrap callback to lambda with a typed argument

asyncMethod().addListener((Future<String> f) -> callback(f));

Maybe it can be done better, IDK.

Sergey Gornostaev
  • 6,481
  • 3
  • 19
  • 32
0

The options you have are either:

  1. use a lambda (shorter than a full anonymous class, but still not optimal):

asyncMethod().addListener((GenericFutureListener<Future<String>>) future -> Application.callback(future))

  1. Fix the parameter of your callback to:

private static void callback(Future<? super String> future) {

from simple Future<String> future, this way you can use callback too.

Note: If you are getting confused about the ? extends vs ? super generics issue, I have this SO post bookmarked for the same reason.

Gergely Bacso
  • 12,757
  • 2
  • 40
  • 61
  • No, same problem `incompatible types: capture#1 of ? super String cannot be converted to String`. – Hivemaster Jan 17 '19 at 10:21
  • @Hivemaster, I tried both before I posted my answer. They are compiling nicely. This is on Java 1.8.0_161, but I do not think later versions would differ in this. Can you check again? – Gergely Bacso Jan 17 '19 at 10:41
  • I rechecked, you are right, now the error occurs in another place - at `future.getNow()`. – Hivemaster Jan 17 '19 at 11:04
  • It works if I add an explicit cast to String but it looks like a crutch. – Hivemaster Jan 17 '19 at 11:11
  • @Hivemaster, This post: https://stackoverflow.com/a/48393422/821786 gives one explanation on why this usage of generics in this case is a good choice. Nevertheless I am with you. I do not like the implementation as it is, but I think *you will need to* use one of these crutches, simply because you are forced to by the library. – Gergely Bacso Jan 17 '19 at 12:22
  • Thanks for your help. I'll wait a little more before choosing the answer. – Hivemaster Jan 17 '19 at 12:25