使用@Builder导致无法创建无参构造方法的解决

 更新时间:2023年12月15日 15:10:51   作者:搏·梦  
这篇文章主要介绍了使用@Builder导致无法创建无参构造方法的解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

1. 前言

在创建实体类的时候,有时候参数过于多,如果使用有参数的构造函数,实在看起来不是很优雅,一般都会想使用@Builder构建者模式来进行创建对象,不仅仅优雅,而且还方便。

当偶然机会发现,如果使用了@Builder,该实体类会失去无参构造方法

具体现象如下:

当不加任何注解的时候,完成正常:

当加了@Builder的时候,则会直接出现下面的错误,提示没有无参的构造函数:

2. 先说结论

由于没有时间深入查看@Builder的源码,但是可以从编译之后的字节码得出结论: 实体类使用了@Builder,会有全参构造函数,没有默认无参构造函数,即无法使用默认无参构造函数。

解决方法:

  • 在实体类上同时加上:@Builder、@AllArgsConstructor、@NoArgsConstructor
  • 手写全部有参构造方法,以及 无参构造方法
  • 手写个默认无参构造方法,并加上@Tolerate
@Builder
public class demoBuilderEntry {
    private String name;
    private String sex;

    @Tolerate
    public demoBuilderEntry() {
    }
}

3. 演示

若不知道怎么查看java反编译字节码内容,可以看一下:

Java如何进行反编译生成.java文件(javap、jad下载安装使用)

1.当实体类不加任何东西:

public class demoBuilderEntry {
    private String name;
    private String sex;
}

可以看见是默认有无参构造函数

public class demoBuilderEntry {

    public demoBuilderEntry() {
    }

    private String name;
    private String sex;
}

2.当实体类加上@Builder注解:

@Builder
public class demoBuilderEntry {
    private String name;
    private String sex;
}

可以看出:无参构造函数已不存在,只剩全参构造函数

public class demoBuilderEntry {
    public static class demoBuilderEntryBuilder {

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

        public demoBuilderEntryBuilder sex(String sex) {
            this.sex = sex;
            return this;
        }

        public demoBuilderEntry build() {
            return new demoBuilderEntry(name, sex);
        }

        public String toString() {
            return (new StringBuilder()).append("demoBuilderEntry.demoBuilderEntryBuilder(name=").append(name).append(", sex=").append(sex).append(")").toString();
        }

        private String name;
        private String sex;

        demoBuilderEntryBuilder() {
        }
    }

    demoBuilderEntry(String name, String sex) {
        this.name = name;
        this.sex = sex;
    }

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

    private String name;
    private String sex;
}

因此,如下图,一定会报错:

有人会说:没有无参怎么了,也没有什么事情,反正需要构造。

但像spring这种,我们可以从配置文件中注入属性,如@ConfigurationProperties,它们的做法是先创建该类对象,使用无参构造函数,然后再调用set方法,此时,你没有默认无参构造方法,必然会失败,毕竟连对象都没有创建成功。

具体失败案例可以看:实体类使用@Builder,导致@ConfigurationProperties注入属性失败

3.如果需要无参构造函数,那就手动添加,在实体类上,再加上@NoArgsConstructor也无效。

根据下图可以看见,似乎没有报错

当运行的时候,则报错如下:与实际参数列表不符,显然是无法通过加@NoArgsConstructor创建默认无参构造函数

4. 解决方法

1. 在实体类上再加上@AllArgsConstructor即可

根据下图查看,似乎也没有问题:

点击运行,查看结果的时候,居然可以运行成功如下:

反手我们去看一下反编译:

public class demoBuilderEntry {
    public static class demoBuilderEntryBuilder {
        // builder 的代码省略,没有粘出来
    }
    
    public static void main(String args[]) {
        System.out.println(new demoBuilderEntry());
    }

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

    public demoBuilderEntry(String name, String sex) {
        this.name = name;
        this.sex = sex;
    }
	// 无参构造函数有了
    public demoBuilderEntry() {
    }

    private String name;
    private String sex;
}

2. 手写个无参构造函数并加上@Tolerate

@Tolerate:中文:容许,通俗来说,被该注解加上的方法,让lombok容许它们存在。

/**
 * Put on any method or constructor to make lombok pretend it doesn't exist,
 * i.e., to generate a method which would otherwise be skipped due to possible conflicts.
 */
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.SOURCE)
public @interface Tolerate {
}

测试:

3. 手写有参无参构造方法

这种方法是最简单粗暴的,但是代码可能会没有那么简洁:

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • IDEA中git对于指定文件进行版本控制的全过程

    IDEA中git对于指定文件进行版本控制的全过程

    用户在IDEA中遇到默认提交所有修改的问题,通过配置.gitignore和.git/info/exclude忽略特定文件,并利用vcs.xml指定版本控制范围,实现精准版本管理,本文通过图文给大家介绍了IDEA中git对于指定文件进行版本控制的全过程,需要的朋友可以参考下
    2025-05-05
  • java基于odbc连接oracle的实现方法

    java基于odbc连接oracle的实现方法

    这篇文章主要介绍了java基于odbc连接oracle的实现方法,结合实例形式分析了连接操作的具体步骤与相关实现技巧,需要的朋友可以参考下
    2016-09-09
  • Java面试岗常见问题之ArrayList和LinkedList的区别

    Java面试岗常见问题之ArrayList和LinkedList的区别

    ArrayList和LinkedList作为我们Java中最常使用的集合类,很多人在被问到他们的区别时,憋了半天仅仅冒出一句:一个是数组一个是链表。这样回答简直让面试官吐血。为了让兄弟们打好基础,我们通过实际的使用测试,好好说一下ArrayList和LinkedList的区别这道经典的面试题
    2022-01-01
  • MyBatis框架关联映射实例详解

    MyBatis框架关联映射实例详解

    这篇文章主要介绍了MyBatis框架关联映射,关系映射主要处理复杂的SQl查询,如子查询,多表联查等复杂查询,应用此种需求时可以考虑使用,需要的朋友可以参考下
    2022-11-11
  • springboot 自定义LocaleResolver实现切换语言

    springboot 自定义LocaleResolver实现切换语言

    我们在做项目的时候,往往有很多项目需要根据用户的需要来切换不同的语言,使用国际化就可以轻松解决。这篇文章主要介绍了springboot 自定义LocaleResolver切换语言,需要的朋友可以参考下
    2019-10-10
  • maven中的scope与systemPath用法

    maven中的scope与systemPath用法

    这篇文章主要介绍了maven中的scope与systemPath用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • java基于Apache FTP点断续传的文件上传和下载

    java基于Apache FTP点断续传的文件上传和下载

    本篇文章主要介绍了java基于Apache FTP点断续传的文件上传和下载,利用FTP实现文件的上传和下载,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2016-11-11
  • 通过实例学习JAVA对象转成XML输出

    通过实例学习JAVA对象转成XML输出

    这篇文章主要介绍了通过实例学习JAVA对象转成XML输出,做流程图的项目时,新的流程定义为xml的,需要对xml与java对象进行互转,下面我们来深入学习,需要的朋友可以参考下
    2019-06-06
  • jsp+dao+bean+servlet(MVC模式)实现简单用户登录和注册页面

    jsp+dao+bean+servlet(MVC模式)实现简单用户登录和注册页面

    这篇文章主要介绍了jsp+dao+bean+servlet(MVC模式)实现简单用户登录和注册页面,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • SpringBoot实现性能翻倍的五种配置方案

    SpringBoot实现性能翻倍的五种配置方案

    在当今高并发的互联网环境下,微服务架构的性能优化成为了开发者必须面对的挑战,SpringBoot作为Java生态中最流行的微服务框架之一,其默认配置虽然能满足大多数场景需求,但在极端性能要求下往往显得力不从心,本文将揭示5个常被开发者忽略的SpringBoot配置项
    2026-01-01

最新评论