.withValidator() with Spring Boot WebFlux

Hello,

could someone show me an example how .withValidator() works with Spring Boot WebFlux (Mono, Flux)?

Something simple:
User A enters e-mail address and .withValidator() checks if e-mail address exists in database already.

I dont know how to do it. Im stucking here:

			binder.forField(txtEmailAddress).asRequired("Email address required")
					.withValidator(new EmailValidator("Email wrong"))
					.withValidator(email -> {
						
						// how can I check the entered e-mail if it exists in database? how can I return therefore true/false from Mono?

					}, "Email exists already")
					.bind(User::getEmailAddress, User::setEmailAddress);

I hope someone can help me. Thank you

WebFlux operations involving Mono or Flux are asynchronous operations, whereas a validator using with Binder needs to return a result immediately. To deal with this, you can use e.g. the block() method defined on Mono to explicitly wait for the asynchronous operation to complete.

Assuming you have a service method for checking for an email that returns a Mono<Boolean>, you could thus implement your validator along the lines of return service.checkIfEmailExists(email).block();.

Doing things in this way does on the other hand mean that you’re not getting any benefits from using WebFlux, but only some overhead from passing the task back and forth between threads. It would be slightly more efficient to simply use a non-asynchronous way of querying the database instead.

//edit:
Hello Leif Åstrand,

thank you very much for your help.

I have another question to the vaadin community:
My simple application has a registration, login and chat site. I would like to implement the chat with the help of WebFlux.
Do you think that I should not use a Validator (or classes that need the result immediately) and do everything reactive?

Thank you for your help guys!

The main point with WebFlux is to reduce the memory consumption of a server by reducing the number of request handling threads. The application logic starts an asynchronous database query and then immediately returns control back to the framework, which means that the framework can handle another request on that thread instead of keeping that thread blocked while waiting for the query result. Once the query completes and the originally returned Mono is resolved, the result will be used to send a response to the browser.

Using block() would typically not directly destroy anything, but it may either cause more request handling threads to be created or alternatively cause the server to queue requests until a thread is available. This negates the benefits of an asynchronous approach like WebFlux.

Vaadin is not designed for asynchronous processing of user events. Once you return from e.g. a value change listener (which is how validators are triggered), Vaadin assumes that all processing has finished and then Vaadin will immediately send a response to the browser based on the changes that were done by that value change listener. This helps keep application logic simple and easy to reason about, but it does also mean that more request handling threads are needed and thus also that the server will need to allocate more memory for those threads.

It is still possible to do asynchronous processing with Vaadin, but you then need to enable @Push which will make Vaadin keep a WebSocket connection open for passing instructions back to the browser instead of doing everything in a request-response cycle. When doing things in this way, you have to structure your application logic in a more complicated way since any updates to Vaadin components must be done through the access() method to protect against concurrent modifications and so that Vaadin can know when updates should be pushed out to the browser.

Most APIs in Vaadin are designed around the simpler programming model based on synchronous request-response cycles rather than the more complex asynchronous approach. This is the case with e.g. validators in Binder. If you want to do validation asynchronously, then you have to do the validation manually and it’s up to you to take care of pushing out changes to the browser when the validation status is updated asynchronously.

Hello,

thank your for the help Leif Åstrand.

does it mean that WebFlux is not recommended to use in combination with Vaadin?!

I have another problem with WebFlux:

I have a router class:


@Configuration
public class UserRouter {

@Bean
public RouterFunction<ServerResponse> route(UserHandler userHandler) {
	return RouterFunctions.route(GET("/hello"), userHandler::hello);
}

@Bean
public RouterFunction<ServerResponse> getUser(UserHandler userHandler) {
	return RouterFunctions.nest(path("/api/users"), RouterFunctions.route(GET("/{id}"), userHandler::get));
}

and

a handler class:


@Component
public class UserHandler {
	
	private  UserService userService;
	
	@Autowired
	public UserHandler(UserService userService) {
		this.userService = userService;
	}
	
	public Mono<ServerResponse> hello(ServerRequest request) {
		return ServerResponse.ok().contentType(MediaType.TEXT_PLAIN)
				.body(BodyInserters.fromObject("Hello world!"));
	}
	
    public Mono<ServerResponse> get(ServerRequest request) {
        String userId = request.pathVariable("id");

        return userService
                .findById(userId)
                .flatMap(user -> ServerResponse.ok().body(Mono.just(user), User.class))
                .switchIfEmpty(ServerResponse.notFound().build());
    }

Everytime I try to access to /hello or /api/users/ I get the following message:
Could not navigate to ‘’
Reason: Couldn’t find route for ‘’

But if I use a simple RestController (not the functional way with routers and handlers) it works.

Thank you in advance.

It’s relatively ok to use WebFlux and Vaadin side-by-side (provided the other problem you’re describing is resolved). Using Flux or Mono (which are actually part of Spring’s Reactor project and only indirectly related to WebFlux) in UI logic that is implemented with Vaadin is possible for the sake of integrating with existing systems (by using .block()) but it’s not recommended as a general practice.

I’m not entirely sure about your problem with not finding routes. My guess is that it’s somehow related to servlet mappings - you would most likely have to ensure the servlet that handles WebFlux requests is specifically configured to handle only handle request to some specific URLs and then let the servlet that handles Vaadin requests (in you case probably Spring’s generic dispatcher servlet) handle everything else.

I would like to use the functional way (= router and handler classes) of Spring Boot (WebFlux) but I am stucking currently. Vaadin cannot find the Routes that I set in my UserRouter class.

Maybe I am asking too much but could you provide some links/tutorials to Spring’s generic Dispatcher Servlet (how to set up that what you said)?

I searched for it but could not find anything specific that I understand.

I am relatively new to Spring and Vaadin. I appreciate every help I get.
Thank you very much!