@Builder注解在子类中使用遇到的问题

  • Post author:
  • Post category:其他




场景

在项目开发中,需要基于某个类进行一些字段的拓展,那么自然而然想到的做法是extends该类。而两个类都需要使用@Builder进行构造。代码如下:

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class EmployeeDto {
    private String companyId;
    private String jobNo;
    private Integer gender;
    private Integer age;
}
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class HardwareEmployeeDto extends EmployeeDto{
    private String title;
}

使用时:

@GetMapping(value = "/v1/builder/test")
public void testBuilder(){
    HardwareEmployeeDto hardwareEmployeeDto = HardwareEmployeeDto.builder().build();
}



问题

本来想现在直接build一个子类HardwareEmployeeDto,同时也需要给父类赋值,但是此时无法对父类的字段进行赋值,只能给子类的title字段赋值。

在这里插入图片描述

就算只赋值title,编译也会报错

@GetMapping(value = "/v1/builder/test")
public void testBuilder(){
    HardwareEmployeeDto hardwareEmployeeDto = HardwareEmployeeDto.builder().title("Hardware Department").build();
    System.out.println(hardwareEmployeeDto);
}

在这里插入图片描述

这个报错是说明子类尝试申明具有跟父类相同名称的builder,默认的构造器都叫builder(),此时可以给子类的构造器自定义一个新名字,使用子类的构造器进行构造。

@Data
@Builder(builderMethodName = "hardwareEmployeeBuilder")
@AllArgsConstructor
@NoArgsConstructor
public class HardwareEmployeeDto extends EmployeeDto{
    private String title;
}
@GetMapping(value = "/v1/builder/test")
public void testBuilder(){
    HardwareEmployeeDto hardwareEmployeeDto = HardwareEmployeeDto.hardwareEmployeeBuilder().title("Hardware Department").build();
    System.out.println(hardwareEmployeeDto);
}

输出内容

HardwareEmployeeDto(title=Hardware Department)

这样是可以编译通过,正常运行,但是还是无法给父类赋值



解决

  • 子类增加构造函数,通过构造函数给父类字段赋值,并且使用@Builder注解自定义构造器名字
@Data
@AllArgsConstructor
@NoArgsConstructor
public class HardwareEmployeeDto extends EmployeeDto{

    @Builder(builderMethodName = "hardwareEmployeeBuilder")
    public HardwareEmployeeDto(String companyId, String jobNo, Integer gender, Integer age, String title) {
        super(companyId, jobNo, gender, age);
        this.title = title;
    }

    private String title;

}
@GetMapping(value = "/v1/builder/test")
public void testBuilder(){
    HardwareEmployeeDto hardwareEmployeeDto = HardwareEmployeeDto.hardwareEmployeeBuilder()
            .title("Hardware Department")
            .companyId("888")
            .age(18)
            .gender(0)
            .jobNo("1")
            .build();
    System.out.println("jobNo is : " + hardwareEmployeeDto.getJobNo());
}
  • 换成使用@SuperBuilder注解

将子类和父类都换成@SuperBuilder注解,子类也不必指定构造器名称。

@Data
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
public class EmployeeDto {
    private String companyId;
    private String jobNo;
    private Integer gender;
    private Integer age;
}
@Data
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
public class HardwareEmployeeDto extends EmployeeDto{

    private String title;

}
    @GetMapping(value = "/v1/builder/test")
    public void testBuilder(){
        HardwareEmployeeDto hardwareEmployeeDto = HardwareEmployeeDto.builder()
                .title("Hardware Department")
                .companyId("888")
                .age(18)
                .gender(0)
                .jobNo("1")
                .build();
        System.out.println("jobNo is : " + hardwareEmployeeDto.getJobNo());
    }


注意

  1. @SuperBuilder和@Builder在父类和子类中不能混用
  2. @SuperBuilder在所有的父类和子类中都必须使用上,缺一不可。


另:@SuperBuilder(toBuilder = true)用法

@SuperBuilder的toBuilder默认是false,如果置为true,需要所有的父类也都设置该字段为true。设置了true之后,所有的类的实例会有toBuilder方法,是一个

深拷贝

的方法,不会覆盖原来的实例的值,而是生成一个新的实例对象赋上新值。

@Data
@SuperBuilder(toBuilder = true)
@AllArgsConstructor
@NoArgsConstructor
public class EmployeeDto {
    private String companyId;
    private String jobNo;
    private Integer gender;
    private Integer age;
}
@Data
@SuperBuilder(toBuilder = true)
@AllArgsConstructor
@NoArgsConstructor
public class HardwareEmployeeDto extends EmployeeDto{

    private String title;

}
@GetMapping(value = "/v1/builder/test")
public void testBuilder(){
    HardwareEmployeeDto hardwareEmployeeDto = HardwareEmployeeDto.builder()
            .title("Hardware Department")
            .companyId("888")
            .age(18)
            .gender(0)
            .jobNo("1")
            .build();
    HardwareEmployeeDto build = hardwareEmployeeDto.toBuilder().jobNo("2").age(28).build();
    System.out.println("jobNo is : " + hardwareEmployeeDto.getJobNo());
    System.out.println("jobNo is : " + build.getJobNo());
}

输出:

jobNo is : 1
jobNo is : 2



版权声明:本文为weixin_43554422原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。