Java Vavr:如何整合Either左侧的Validation与DomainError错误
解决Vavr中Either业务错误与Validation校验错误的整合问题
核心问题分析
你当前的代码里,findBookById返回的Either<BookError, Book>和校验返回的Validation<Seq<String>, BookCreateDto>属于不同的错误体系,无法直接串联。需要把校验错误转换为和BOOK_NOT_FOUND同类型的BookError,并用flatMap替代map展开Validation结果,实现错误流的统一。
步骤1:扩展BookError以承载校验错误
先修改BookError枚举,让它能保存校验错误列表:
public enum BookError { BOOK_NOT_FOUND, BOOK_VALIDATION_ERROR(Seq.empty()); private final Seq<String> errors; BookError() { this.errors = Seq.empty(); } BookError(Seq<String> errors) { this.errors = errors; } public Seq<String> getErrors() { return errors; } }
步骤2:重构业务方法流程
调整代码逻辑,保留原Book实体的同时将校验结果转为统一的Either类型,确保错误流一致:
public Either<BookError, BookResponse> updateBookById(final Long bookId, final BookUpdateDto toUpdate) { return findBookById(bookId) .toEither(BookError.BOOK_NOT_FOUND) // 用flatMap展开校验结果,统一错误类型 .flatMap(originalBook -> { // 执行DTO校验 Validation<Seq<String>, BookCreateDto> validation = bookValidation.validate(toUpdate); // 将Validation转换为Either,把校验错误包装为BookError return validation.toEither() .mapLeft(validationErrors -> BookError.BOOK_VALIDATION_ERROR(validationErrors)) // 保留原Book和校验后的DTO,方便后续更新 .map(validatedDto -> Tuple.of(originalBook, validatedDto)); }) // 执行书籍更新与保存 .map(tuple -> { Book updatedBook = tuple._1.update(tuple._2); return bookRepository.save(updatedBook); }) // 转换为响应DTO .map(Book::response); }
关键调整说明
- 用flatMap替代map处理校验:
map会把Either包装成Either<BookError, Validation<...>>,而flatMap可以直接展开Validation转换后的Either,让整个流程的错误类型统一为BookError。 - 保留原Book实体:之前的代码把原Book转成response后丢失,没法用于更新操作,通过
Tuple组合原Book和校验后的DTO,确保更新逻辑能基于原始实体执行。 - 统一错误载体:把校验错误列表包装到
BOOK_VALIDATION_ERROR中,上层可以通过判断BookError类型,分别处理“书籍不存在”和“校验失败”两种业务场景。
内容的提问来源于stack exchange,提问作者hare-dev
相关产品推荐
相关产品推荐

