简体   繁体   中英

When trying to use reactive data I am getting invalid property 'id' of bean class [reactor.core.publisher.MonoOnAssembly]

I am trying to use thymeleaf form along with single valued reactive data stream. Using spring boot 2.1.3, thymeleaf 3.0.11 and webflux. My POJO is:

@Getter
@Setter
@NoArgsConstructor
public class RecipeCommand {
    private String id;
    private String description;
}

controller is:

@GetMapping("/recipe/{id}/update")
public String updateRecipe(Model model, @PathVariable String id){

    Mono<RecipeCommand> recipeCommandMono = recipeService.getRecipeCommandById(id);
    model.addAttribute("recipe", recipeCommandMono);
    return "recipes/recipeform";
}

where recipes/recipeform is thymeleaf form to update recipe:

<form  th:object="${recipe}" th:action="@{/post}" method="post">
    <input type="hidden" th:field="*{id}"/>

Application run but when trying to update recipe I got below error:

Caused by: org.springframework.beans.NotReadablePropertyException: Invalid property 'id' of bean class [reactor.core.publisher.MonoOnAssembly]: Bean property 'id' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?

Any idea how to use thymeleaf form with reactive streams.

POM:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0   http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.gabriel</groupId>
    <artifactId>spring-recipe</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-recipe</name>

    <properties>
        <java.version>11</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>bootstrap</artifactId>
            <version>4.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>popper.js</artifactId>
            <version>1.14.7</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-failsafe-plugin</artifactId>
                <version>3.0.0-M3</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>integration-test</goal>
                            <goal>verify</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

You are trying to pass Mono to your template. Instead of that you can wrap Mono with IReactiveDataDriverContextVariable object. IReactiveDataDriverContextVariable works with Flux so you should use flux() method to convert Mono to Flux .

@GetMapping("/recipe/{id}/update")
public String updateRecipe(Model model, @PathVariable String id){

    Mono<RecipeCommand> recipeCommandMono = recipeService.getRecipeCommandById(id);
    IReactiveDataDriverContextVariable recipe = new ReactiveDataDriverContextVariable(recipeCommandMono.flux(), 1);
    model.addAttribute("recipes", recipe);
    return "recipes/recipeform";
}

change thymeleaf part (variable recipes is now async list)

<div th:each="recipe : ${recipes}">
    <form  th:object="${recipe}" th:action="@{/post}" method="post">
        <input type="hidden" th:field="*{id}"/>

I switched to spring boot 2.2.2.RELEASE. It solved problem. Now thymeleaf accepts Mono when passed as model attribute. No changes were required neither to controller nor to form template.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM