javaspring-webfluxproject-reactorvavr

Unexpected return type of vavr's Either in reactor


There are two simple methods using vavr's Either.

public Either<String, Integer> testEither(int s) {
    if (s == 0)
        return Either.left("Wrong");
    return Either.right(s);
}

public Mono<Either<String, Integer>> testReactorEither(int s) {
    return Mono.just(s).filter(x -> x == 0).map(Either::right)
            .switchIfEmpty(Mono.just(Either.left("ERROR")));
}

The testEither works normally, but meanwhile, the testReactorEither raises a compile error of "incompatible types" which says the provided return type of reactor.core.publisher.Mono<io.vavr.control.Either<java.lang.Object,java.lang.Integer>> is incompatible with required return of reactor.core.publisher.Mono<io.vavr.control.Either<java.lang.String,java.lang.Integer>>.

I'm afraid the problem is just because the method of map(Either::right) just defines the Right type of Integer but not do the Left type, and then the return type of the method is Either<?, Integer>. Then the question is how I can get the expected return type in this case?

[UPDATED]

As Hinse mentioned in his comment, the issue is related to the limitation of Java type inference, and some links I found for the problem is listed as follows:

https://bugs.eclipse.org/bugs/show_bug.cgi?id=511252

https://e.printstacktrace.blog/java-type-inference-generic-methods-chain-call/

https://openjdk.java.net/jeps/101


Solution

  • The second example seems to 'lose' the type information for the left side when the map(Either::right) is applied.

    Adding some type 'hints' to the map method call should do the trick. So the testReactorEither will look like this:

    public Mono<Either<String, Integer>> testReactorEither(int s) {
        return Mono.just(s)
                .filter(x -> x == 0)
                .<Either<String, Integer>>map(Either::right)
                .switchIfEmpty(Mono.just(Either.left("ERROR")));
    }