使用@builder时遇到的坑

背景

之前我定义类时,一般不喜欢使用@Builder注解,但组内同事很热衷于使用这个,于是我也抱着跟上新技术的步伐,对DTO对象类添加了@Builder注解。

当测试验证时,出现了异常:

java.lang.InstantiationException: com.ctrip.flight.backendservice.flowblock.orderpolicy.web.soa.PassengerBuilder

	at java.lang.Class.newInstance(Class.java:427)
	at com.ctrip.flight.backendservice.flowblock.orderpolicy.web.soa.NewBuilderTest.testBuilderNewInstance(NewBuilderTest.java:18)
Caused by: java.lang.NoSuchMethodException: com.ctrip.flight.backendservice.flowblock.orderpolicy.web.soa.PassengerBuilder.<init>()
	at java.lang.Class.getConstructor0(Class.java:3082)
	at java.lang.Class.newInstance(Class.java:412)
	... 1 more


纳尼,竟然会报错NosuchMethodException???

回归代码

先看下测试代码

@Test
    public void testBuilderNewInstance() throws InstantiationException, IllegalAccessException {
        Class<PassengerBuilder> newBuilderClass = PassengerBuilder.class;

        System.out.println(newBuilderClass.newInstance());
    }

定义的PassengerBuilder类

@Builder
public class PassengerBuilder {

    private String name;

    private int age;
}

再看下生成的.class文件

**根本原因:**在生成的PassengerBuilder.class文件中没有newInstance,所以报错了

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.ctrip.flight.backendservice.flowblock.orderpolicy.web.soa;

public class PassengerBuilder {
    private String name;
    private int age;

    PassengerBuilder(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public static PassengerBuilderBuilder builder() {
        return new PassengerBuilderBuilder();
    }

    public static class PassengerBuilderBuilder {
        private String name;
        private int age;

        PassengerBuilderBuilder() {
        }

        public PassengerBuilderBuilder name(String name) {
            this.name = name;
            return this;
        }

        public PassengerBuilderBuilder age(int age) {
            this.age = age;
            return this;
        }

        public PassengerBuilder build() {
            return new PassengerBuilder(this.name, this.age);
        }

        public String toString() {
            return "PassengerBuilder.PassengerBuilderBuilder(name=" + this.name + ", age=" + this.age + ")";
        }
    }
}

解决方案

在类上使用@Builder时,同时加上另外两个注解,完美解决问题。

@NoArgsConstructor
@AllArgsConstructor

加上这两个注解后,编译类后会生成无参构造函数和有参构造函数

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.ctrip.flight.backendservice.flowblock.orderpolicy.web.soa;

public class PassengerBuilder {
    private String name;
    private int age;

    public static PassengerBuilderBuilder builder() {
        return new PassengerBuilderBuilder();
    }

    public PassengerBuilder() {
    }

    public PassengerBuilder(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public static class PassengerBuilderBuilder {
        private String name;
        private int age;

        PassengerBuilderBuilder() {
        }

        public PassengerBuilderBuilder name(String name) {
            this.name = name;
            return this;
        }

        public PassengerBuilderBuilder age(int age) {
            this.age = age;
            return this;
        }

        public PassengerBuilder build() {
            return new PassengerBuilder(this.name, this.age);
        }

        public String toString() {
            return "PassengerBuilder.PassengerBuilderBuilder(name=" + this.name + ", age=" + this.age + ")";
        }
    }
}

总结@Builder的坑

  • 在类上使用了 @Builder 注解,那么需要手动添加一个无参构造函数,否则有些序列化框架需要通过 newInstance 构造对象时会报错。
    【正如本文上述分析】

  • 在类上使用了 @Builder 注解,那么不能再在构造函数或方法上使用 @Builder 注解,否则会导致重复生成构造器类。

  • 给某个属性设置一个默认值,那么需要在属性上使用 @Builder.Default 注解,否则默认值会被忽略,无法达到设置默认值的功能。

  • 如果想让子类继承父类的属性,那么需要在子类的全参构造函数上使用 @Builder 注解,并且在父类上使用 @AllArgsConstructor 注解,否则子类的构造器类不会包含父类的属性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值