javaasynchronousgenericsinheritanceasync-await

Inherit from the generic class CompletableFuture


I wish to write async/await code which is JS-friendly, however, my class inheritance doesn't seem to work:

import java.util.concurrent.CompletableFuture;

class Main {
    public static class Promise<T> extends CompletableFuture<T>{}
    
    public static void main(String[] args) {
        System.out.println(System.getProperty("java.version"));
        // This works:
        CompletableFuture<String> p1 = Promise.supplyAsync(()->{
            return "foobar";
        });
        // This doesn't, but i need this:
        Promise<String> p2 = Promise.supplyAsync(()->{
            return "foobar";
        });
    }
}

The tricky part is I need to return as Promise<T> not CompletableFuture<T>, making a JS-friendly util.

Error:

ERROR!
/tmp/kpS1aJoUkj/Main.java:13: error: incompatible types: no instance(s) of type variable(s) U exist so that CompletableFuture<U> conforms to Promise<String>
        Promise<String> p2 = Promise.supplyAsync(()->{
                                                ^
  where U is a type-variable:
    U extends Object declared in method <U>supplyAsync(Supplier<U>)
1 error

If a cast added to the right side of p2, the error is:

ERROR!
Exception in thread "main" java.lang.ClassCastException: class java.util.concurrent.CompletableFuture cannot be cast to class Main$Promise (java.util.concurrent.CompletableFuture is in module java.base of loader 'bootstrap'; Main$Promise is in unnamed module of loader 'app')
    at Main.main(Main.java:13)

Tested on https://www.programiz.com/java-programming/online-compiler/


Solution

  • The error you get is because supplyAsync() returns a CompletableFuture and you are trying to assign it to a Promise. The assignment correctly fails to compile because a CompletableFuture is not a Promise.

    You can work around this by writing your Promise class to be constructible from a CompletableFuture - perhaps by holding the CompletableFuture in a private field and delegating its methods to it.

    Then you can override your Promise.supplyAsync to return a Promise which contains the CompletableFuture returned by its super class.