You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SpringBoot+Thymeleaf+Lombok读取属性报错:NotReadablePropertyException

问题解决:Thymeleaf绑定实体类属性时出现NotReadablePropertyException

问题场景

定义了带有@Builder、@Data、@AllArgsConstructor、@NoArgsConstructor注解的BlogSearchDataPayload实体类,其中blogCategory字段有默认值。控制器中将BlogSearchDataPayload.builder()添加到ModelMap作为searchFilter,在Thymeleaf模板通过th:field绑定searchFilter.blogCategory时,抛出NotReadablePropertyException,提示属性不可读或getter无效。

实体类代码

@Builder
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BlogSearchDataPayload {

    String langCode;
    String blogCategory = BlogCategoryEnum.all.name();

}

控制器代码

@GetMapping({"/blogs", "/"})
public String index(@RequestParam(name = "langCode", required = false) String langCode,
                    @RequestParam(name = "blogCategory", required = false) String blogCategory,
                    final ModelMap model) throws ExecutionException, InterruptedException {

    model.addAttribute("blogItems",
            blogItems(langCode, blogCategory, null, null));
    model.addAttribute("searchFilter", BlogSearchDataPayload.builder());

    return "blogs";
}

模板代码

<select name="blogCategory" th:field="*{searchFilter.blogCategory}" th:id="blogCategory" onchange="updateAction()">
    <option value="all">All</option>
    <option value="transits">Transits</option>
    <option value="natalchart">Natal Chart</option>
    <option value="solarreturn">Solar Return</option>
    <option value="synastry">Synastry</option>
</select>

报错信息

Caused by: org.springframework.beans.NotReadablePropertyException: Invalid property 'blogCategory' of bean class [com.mysticriver.web.payload.BlogSearchDataPayload$BlogSearchDataPayloadBuilder]: Bean property 'blogCategory' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
    at org.springframework.beans.AbstractNestablePropertyAccessor.getPropertyValue(AbstractNestablePropertyAccessor.java:627)
    at org.springframework.beans.AbstractNestablePropertyAccessor.getPropertyValue(AbstractNestablePropertyAccessor.java:617)

原因分析

  1. 控制器传入Model的是BlogSearchDataPayloadBuilder对象(BlogSearchDataPayload.builder()返回的是Builder实例),而非BlogSearchDataPayload实体类实例。Lombok的@Builder生成的Builder类仅提供链式设置属性的方法(如blogCategory(xxx)),没有标准的getter方法(如getBlogCategory()),Thymeleaf的th:field需要通过getter访问属性,因此抛出异常。
  2. 实体类中blogCategory的字段初始化值不会被Lombok的@Builder自动识别,即使构建实例,默认值也不会生效,需要额外配置。

解决方案

步骤1:将Builder构建为实体类实例

修改控制器代码,调用build()方法生成BlogSearchDataPayload实例,再传入Model:

@GetMapping({"/blogs", "/"})
public String index(@RequestParam(name = "langCode", required = false) String langCode,
                    @RequestParam(name = "blogCategory", required = false) String blogCategory,
                    final ModelMap model) throws ExecutionException, InterruptedException {

    model.addAttribute("blogItems",
            blogItems(langCode, blogCategory, null, null));
    // 构建实体实例而非传入Builder
    BlogSearchDataPayload searchFilter = BlogSearchDataPayload.builder().build();
    model.addAttribute("searchFilter", searchFilter);

    return "blogs";
}

步骤2:让Builder识别字段默认值

在实体类的blogCategory字段上添加@Builder.Default注解,确保Builder构建实例时使用字段的初始化默认值:

@Builder
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BlogSearchDataPayload {

    String langCode;
    @Builder.Default // 添加该注解让Builder识别默认值
    String blogCategory = BlogCategoryEnum.all.name();

}

完成以上修改后,Thymeleaf就能正常通过th:field绑定searchFilter.blogCategory属性,异常即可解决。

内容的提问来源于stack exchange,提问作者Nunyet Calçada

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 16:30:20