Search code examples
javathymeleafspring-webflux

Webflux Reactive objects not resolved before rendering Thymeleaf View


When I try to render my view in Thymeleaf I get an error Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'currentTemperature' cannot be found on object of type 'reactor.core.publisher.MonoMapFuseable' - maybe not public or not valid?

The Spring WebFlux documentation states "model attributes that have a reactive type wrapper are resolved to their actual values", but passing a Mono<> to the view as a Model gives me the error above.

  @RequestMapping(path = "/")
  @GetMapping
  public String home(Model model) {
    Mono<ThermostatState> thermostatState = thermostatClient.fetchThermostatState();
    model.addAttribute("thermostatState", thermostatState);
    return "home";
  }

Blocking the Mono<> and unwrapping the internal value makes the template render unchanged, but kinda eliminates the point of using the reactive libraries.

  @RequestMapping(path = "/")
  @GetMapping
  public String home(Model model) {
    Mono<ThermostatState> thermostatState = thermostatClient.fetchThermostatState();
    ThermostatState unwrappedState = thermostatState.block();
    model.addAttribute("thermostatState", unwrappedState);
    return "home";
  }

The project is entirely dependent on the spring starter dependencies and doesn't have an explicit configuration class.


Solution

  • I was able to resolve this issue by removing the following from my pom.xml

        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-data-rest</artifactId>
        </dependency>
    

    This was added without complaint by the Spring starter, but it is quasi-incompatible with Webflux. The application runs without complaint, but you can kinda tell something is going wrong when it reports in the startup logs that it is starting with Tomcat, not Netty. This is an indication it is running as an old-style MVC app, not a Webflux app. Having discovered this, I was able to find an explanatory answer on another question: https://stackoverflow.com/a/48418409/23276 (different symptoms, but same answer). There's a little more explanation here: https://stackoverflow.com/a/51378560/23276

    I was able to prove things worked initially by creating a single-dependency sample app that worked the way I expected and saw in the documentation. Then I tried removing the different dependencies one by one until I found the conflict.

    When troubleshooting this, I was impeded by my IDE doing weird things caching dependencies. It became easier to discover the problem when I dropped to the command line and tried things with mvn clean and mvn spring-boot:run until I found the broken dependency.