Daniel Fernández opened SPR-15551 and commented

In one of the Thymeleaf sample applications using WebFlux, I have a Formatter like this:

public class VarietyFormatter implements Formatter<Variety> {
    ...
    public Variety parse(final String text, final Locale locale) throws ParseException {
        final Integer varietyId = Integer.valueOf(text);
        // There is no Formatter API yet that allows us to return a Publisher, so we need to block
        return this.varietyService.findById(varietyId).block();
    }

}

This is what I think could be a quite common pattern: a Formatter being used for transforming a PK (perhaps coming from a form field) into a complete entity object, coming from the database.

The problem is, the service method that this needs to call is reactive:

public Mono<Variety> findById(final Integer id) {
    ...
}

So either the Formatter#parse() method calls .block(), or it returns Mono<Variety>. But in the latter case, that would mean changing the formatter class's specification to:

public class VarietyFormatter implements Formatter<Mono<Variety>> {
    ...
}

And this would force us to block at the Formatter#print() method:

public String print(final Mono<Variety> object, final Locale locale) {
    final Variety variety = object.block();
    return (variety != null ? variety.getId().toString() : "");
}

Why not return Mono<String> there? because the Formatter<T> interface extends from Printer<T>, and the Printer#print(...) method is defined as:

String print(T object, Locale locale);

So it seems to me that there is no way to support this scenario in a non-blocking manner right now…


Affects: 5.0 RC1

Comment From: bclozel

Sorry for replying so late. I don't think the Formatter interface was meant for such use cases involving remote I/O. This resolution should be done at a different stage / using other infrastructure. We don't plan on offering a reactive variant for this contract at the moment. I'm declining this issue as a result.