Java – Spring webflux does not use @ModelAttribute to populate custom objects from path variables

Spring webflux does not use @ModelAttribute to populate custom objects from path variables… here is a solution to the problem.

Spring webflux does not use @ModelAttribute to populate custom objects from path variables

I’m trying to tweak an application that works well with Spring MVC but behaves differently than Spring WebFlux

Here is my code using Spring Boot 5 – Spring MVC:

Controller :

@RestController
public class MyRestController {

@GetMapping("/test/{id}/{label}")
    public ResponseEntity<Payload> test(@ModelAttribute Payload payload) {
        return new ResponseEntity<>(payload,HttpStatus.OK);
    }
}

Payload object:

public class Payload {

@NotNull
    private int id;

private String label;

public Payload() {}

public String getLabel() {
        return label;
    }

public void setLabel(String label) {
        this.label = label;
    }

public int getId() {
        return id;
    }

public void setId(int id) {
        this.id = id;
    }
}

My pom .xml

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.0.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

I didn’t write any custom converter, Spring automatically populates my payload object and everything is fine.

When I call:

http://localhost:8080/test/25/helloWorld

The response is

{"id":25,"label":"helloWorld"}

Then, I just changed my pom .xml, switching from web to webflux

:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.0.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
</dependencies>

My payload object is no longer populated.

When I call:

http://localhost:8080/test/25/helloWorld

The response is

{"id":0,"label":null}

I know I can

write a converter and register it with @ControllerAdvice, but I can’t imagine an automated solution that won’t make it work again because it’s always working with the Spring Web.

Has anyone had the same problem as me?

Thanks,

Julian

Solution

Spring WebFlux reference documentation about @ModelAttribute and The same section in the reference documentation for Spring MVC is different, and the URI path variable is not mentioned

The Pet instance above is resolved as follows:

  • From the model if already added by using Model.
  • From the HTTP session by using @SessionAttributes.
  • From a URI path variable passed through a Converter (see the next
    example).
  • From the invocation of a default constructor.
  • From the invocation of a “primary constructor” with arguments that
    match to Servlet request parameters. Argument names are determined
    through JavaBeans @ConstructorProperties or through runtime-retained
    parameter names in the bytecode.

This is the expected behavior at this point, and there may be a good reason or restriction behind the choice. Feel free to open an enhancement request in Spring Framework for that .

Related Problems and Solutions