为什么@Builder 注解默认父类字段不可见

CustomerCondition customerCondition = new CustomerCondition();

customerCondition.setId(condition.getCustomerId());

customerCondition.setKeyword(condition.getCustomerKeyword());

customerCondition.setPageNum(1);

customerCondition.setPageSize(Integer.MAX_VALUE);

List<CustomerResponse> customerResponseList = customerService.getPage(

CustomerCondition.defaultBuilder()

.id(condition.getCustomerId())

.keyword(condition.getCustomerKeyword())

.build()

).getRecords();

为什么build注解设置父类字段的值,会爆红

根据你提供的代码,问题在于 CustomerCondition.defaultBuilder() 创建的构建器可能没有包含父类 PageRequest 的字段。这是 Lombok @Builder 注解的一个常见限制。

问题分析

  1. 父类字段不可见 :Lombok 的 @Builder 默认只处理当前类中声明的字段,不包含父类字段

  2. 构建器方法缺失defaultBuilder() 返回的构建器可能没有父类的 pageNumpageSize 等方法

解决方案

方案一:使用 @SuperBuilder(推荐)

这是 Lombok 专门用于处理继承关系的构建器注解。

修改 PageRequest 类:

java

复制代码
package com.admin.common;

import lombok.Getter;
import lombok.Setter;
import lombok.experimental.SuperBuilder;

@Getter
@Setter
@SuperBuilder  // 添加这个注解
public class PageRequest {
    private Integer pageNum = 1;
    private Integer pageSize = 20;
    private String keyword;
    // ... 其他字段
}

修改 CustomerCondition 类:

java

复制代码
package com.admin.condition;

import com.admin.common.PageRequest;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;

import java.io.Serializable;
import java.util.List;

@Data
@Schema(description = "客户表")
@SuperBuilder(toBuilder = true)  // 将 @Builder 改为 @SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
public class CustomerCondition extends PageRequest implements Serializable {

    private static final long serialVersionUID = 1L;

    @Schema(description = "客户id")
    private Long id;
    
    @Schema(description = "主键列表")
    private List<Long> ids;

    @Schema(description = "客户状态")
    private String customerStatus;

    @Schema(description = "是否查询客户账户")
    private Boolean isQueryAccount = false;

    @Schema(description = "客户账户条件")
    private CustomerAccountCondition accountCondition;
    
    // 删除之前的 defaultBuilder() 方法,使用 @SuperBuilder 提供的构建器
}

使用方式:

java

复制代码
List<CustomerResponse> customerResponseList = customerService.getPage(
    CustomerCondition.builder()  // 直接使用 @SuperBuilder 生成的构建器
        .pageNum(1)
        .pageSize(Integer.MAX_VALUE)
        .id(condition.getCustomerId())
        .keyword(condition.getCustomerKeyword())
        .build()
).getRecords();

方案二:手动添加父类字段到构建器(如果无法使用 @SuperBuilder)

修改 CustomerCondition 类:

java

复制代码
@Data
@Schema(description = "客户表")
@Builder(builderClassName = "CustomerConditionBuilder", builderMethodName = "hiddenBuilder")
@AllArgsConstructor
@NoArgsConstructor
public class CustomerCondition extends PageRequest implements Serializable {
    
    // ... 字段定义
    
    // 自定义构建器类
    public static class CustomerConditionBuilder {
        // 添加父类字段
        private Integer pageNum = 1;
        private Integer pageSize = 20;
        private String keyword;
        // 其他父类字段...
        
        // 添加父类字段的设置方法
        public CustomerConditionBuilder pageNum(Integer pageNum) {
            this.pageNum = pageNum;
            return this;
        }
        
        public CustomerConditionBuilder pageSize(Integer pageSize) {
            this.pageSize = pageSize;
            return this;
        }
        
        public CustomerConditionBuilder keyword(String keyword) {
            this.keyword = keyword;
            return this;
        }
        
        // 修改 build 方法以包含父类字段
        public CustomerCondition build() {
            CustomerCondition condition = new CustomerCondition();
            // 设置父类字段
            condition.setPageNum(this.pageNum);
            condition.setPageSize(this.pageSize);
            condition.setKeyword(this.keyword);
            // 设置当前类字段
            condition.setId(this.id);
            condition.setIds(this.ids);
            condition.setContractArea(this.contractArea);
            condition.setCustomerCategory(this.customerCategory);
            condition.setCustomerStatus(this.customerStatus);
            condition.setIsQueryAccount(this.isQueryAccount);
            condition.setAccountCondition(this.accountCondition);
            return condition;
        }
    }
    
    // 提供公共的构建器方法
    public static CustomerConditionBuilder builder() {
        return new CustomerConditionBuilder();
    }
}

方案三:使用组合代替继承

如果父类字段不多,可以考虑使用组合:

java

复制代码
@Data
@Schema(description = "客户表")
@Builder(toBuilder = true)
@AllArgsConstructor
@NoArgsConstructor
public class CustomerCondition implements Serializable {

    private static final long serialVersionUID = 1L;

    // 包含 PageRequest 的字段
    @Schema(description = "页码")
    @Builder.Default
    private Integer pageNum = 1;
    
    @Schema(description = "每页条数")
    @Builder.Default
    private Integer pageSize = 20;
    
    @Schema(description = "关键词")
    private String keyword;
    
    // 原有的字段
    @Schema(description = "客户id")
    private Long id;
    
    @Schema(description = "主键列表")
    private List<Long> ids;
    
    // ... 其他字段
}

方案四:简化代码,不使用构建器

既然你之前的代码可以工作,可以直接使用:

java

复制代码
CustomerCondition customerCondition = new CustomerCondition();
customerCondition.setId(condition.getCustomerId());
customerCondition.setKeyword(condition.getCustomerKeyword());
customerCondition.setPageNum(1);
customerCondition.setPageSize(Integer.MAX_VALUE);

List<CustomerResponse> customerResponseList = customerService.getPage(customerCondition).getRecords();

或者在类中添加一个便捷方法:

java

复制代码
// 在 CustomerCondition 类中添加
public static CustomerCondition createDefault() {
    CustomerCondition condition = new CustomerCondition();
    condition.setPageNum(1);
    condition.setPageSize(20);
    condition.setIsQueryAccount(false);
    return condition;
}

// 使用方式
CustomerCondition customerCondition = CustomerCondition.createDefault();
customerCondition.setId(condition.getCustomerId());
customerCondition.setKeyword(condition.getCustomerKeyword());
customerCondition.setPageSize(Integer.MAX_VALUE);

推荐方案

  1. 首选方案一 (使用 @SuperBuilder):

    • 最符合 Lombok 的设计理念

    • 代码最简洁

    • 完全支持继承

  2. 如果无法升级 Lombok 版本(需要 1.18.2+):

    • 使用方案四,保持简单

    • 或者使用方案二的变体

注意事项

  1. Lombok 版本要求@SuperBuilder 需要 Lombok 1.18.2 或更高版本

  2. 依赖更新 :确保所有相关类都正确导入 @SuperBuilder

  3. 编译插件 :确保 IDE 的 Lombok 插件已更新到支持 @SuperBuilder 的版本

选择适合你项目情况的方案。如果项目 Lombok 版本较低且无法升级,建议使用方案四(简化代码)。如果可以升级 Lombok,强烈推荐使用方案一。

相关推荐
一 乐2 小时前
学生宿舍管理|基于springboot + vue学生宿舍管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·助农电商系统
一人の梅雨2 小时前
义乌购商品详情接口进阶实战:批发场景下的精准解析与高可用架构
java·服务器·前端
Dontla2 小时前
Mybatis Introduction (Java ORM Framework)
java·开发语言·mybatis
信码由缰2 小时前
JExten:基于Java模块系统(JPMS)构建健壮的插件架构
java·开发语言·架构
NuageL2 小时前
SpringBoot使用@Scheduled注解实现定时任务
java·spring boot·后端
像少年啦飞驰点、2 小时前
零基础入门 Redis:从“缓存是什么”到手写一个简易购物车系统
java·spring boot·redis·缓存·编程入门·小白教程
短剑重铸之日2 小时前
《SpringCloud实用版》完整技术选型地图
java·后端·spring·spring cloud
南山乐只2 小时前
Qwen Code + OpenSpec 实战指南:AI 驱动开发的从安装到落地
java·人工智能·后端
有味道的男人2 小时前
如何使用招标网API获取项目详情?
java·服务器·前端