Incompatible types while returning Either

I’m using vavr’s Either to control flow of my application and it worked fine, until I didn’t have to mix few domains…

First of all, I got one interface that is shared between domains.

public interface DomainError {
    String getCause();
}

And same for success, when I just want to inform user about that and don’t need to return particular object.

@RequiredArgsConstructor
@Getter
public class SuccessMessage {
    private final String message;
}

Now, each domain implements DomainError like this

public enum UserError implements DomainError {
    USERNAME_ALREADY_EXISTS("Username already exists"),
    INVALID_EMAIL("Provided email address is invalid");

    private final String cause;
    UserError(String cause) {
        this.cause = cause;
    }
    @Override
    public String getCause() {
        return cause;
    }
}

Similar it looks for EmailError which just have another values inside. Now, I have EmailFacade

public class EmailFacade {
    private final SendEmailUseCase sendEmail;
    private final CreateEmailUseCase createEmail;

    public Either<DomainError, SuccessMessage> sendUserVerificationEmail(UUID uuid, String receiver) {
        return sendEmail.send(createEmail.createUserVerificationEmail(uuid, receiver));
    }
}

And one of it’s services returns

class SendEmailUseCase {
    Either<DomainError, SuccessMessage> send(EmailMessage message) {
        if(message == null) return Either.left(EmailError.EMPTY_MESSAGE);
        log.info(message.toString());
        return Either.right(new SuccessMessage("Email sent"));
    }
}

Now, I need to call this from my other domain, which handles registration of user.

In order to do that I wrote this method

Either<DomainError, SuccessMessage> register(RegisterUserDto registerUserDto) {
        if(userRepository.findUser(registerUserDto.getUsername()).isPresent())
            return Either.left(UserError.USERNAME_ALREADY_EXISTS);
        Either<DomainError, User> userCreationResult = User.createUser(registerUserDto);
        return userCreationResult
            .map(user -> {
                userRepository.save(user.toDto());
                final UUID uuid = verificationTokenRepository.generateVerificationToken(user.getUsername());
                return emailFacade.sendUserVerificationEmail(uuid, user.getUsername());
            });
    }

I’m doing few things here, but relevant part is last return statement, all above is working. emailFacade.sendUserVerificationEmail() returns Either<DomainError, SuccessMessage>, same as register() method. But for some reason, I’m getting this error

Error:(28, 17) java: incompatible types: inference variable U has
incompatible bounds
equality constraints: com.johndoe.myapp.domain.SuccessMessage
lower bounds: io.vavr.control.Either<com.johndoe.myapp.domain.DomainError,com.johndoe.myapp.domain.SuccessMessage>

And I seriously can’t understand what went wrong here…

1
Leave a Reply

avatar
1 Comment threads
0 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
1 Comment authors
Jason Recent comment authors
  Subscribe  
newest oldest most voted
Notify of
Jason
Guest

Method map is used to transform value inside container. In your case it gives you value of User and expects that you return transformed value. So in case you are returning Either<DomainError, User> then type of result will be Either<DomainError, Either<DomainError, User>> and it is not what method signature expects as return type. If you wan’t to return Either from function, then you should use flatMap instead, which would flatten result to Either<DomainError, User>: return userCreationResult .flatMap(user -> { //replace map with flatMap userRepository.save(user.toDto()); final UUID uuid = verificationTokenRepository.generateVerificationToken(user.getUsername()); return emailFacade.sendUserVerificationEmail(uuid, user.getUsername()); });