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)
原因分析
- 控制器传入Model的是
BlogSearchDataPayloadBuilder对象(BlogSearchDataPayload.builder()返回的是Builder实例),而非BlogSearchDataPayload实体类实例。Lombok的@Builder生成的Builder类仅提供链式设置属性的方法(如blogCategory(xxx)),没有标准的getter方法(如getBlogCategory()),Thymeleaf的th:field需要通过getter访问属性,因此抛出异常。 - 实体类中
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
相关产品推荐
相关产品推荐

