当前位置:   article > 正文

了解@Builder看了这篇文章就够了_@builder.default

@builder.default

背景

今天在联调接口的时候,前端同学说有个参数没有传值,导致报错了。

我看了下,原因是因为当前对象在mysql中的类型为text。

众所周知,text存储类型在MySQL8中是不能设置默认值的。

所以只能前置到代码中设定默认值。

使用过Lombok的都知道

设置默认值直接在属性字段上添加@Builder.default,然后设置默认值就可以了。

但是在编译的时候,错误出来了:

"无法将类 XX中的构造器 XX应用到给定类型"

 错误示例代码

  1. import lombok.Builder;
  2. import lombok.Data;
  3. @Data
  4. @Builder
  5. public class BuilderTest {
  6. private Integer code;
  7. @Builder.default
  8. private String name="";
  9. }

错误分析

这个错误,根据字面上的意思是调用构造器的时候,属性参数没有构造成功。

根据刚刚加的那个字段来判断,应该是@Builder.default这个地方报错了。

@Builder注解默认用的是全参数构造函数,此时会导致无法new一个无参的构造对象出来。

既然不能默认构造无参,那就直接设定一个无参构造函数就好了。

解决方案

实现方式无非以下两种

直接构造一个无参对象

  1. import lombok.Builder;
  2. import lombok.Data;
  3. @Data
  4. @Builder
  5. public class BuilderTest {
  6. private Integer code;
  7. @Builder.default
  8. private String name;
  9. BuilderTest()
  10. {
  11. }
  12. }

使用@NoArgsConstructor注解

使用后建立一个无参构造函数。

  1. import lombok.Builder;
  2. import lombok.Data;
  3. @Data
  4. @NoArgsConstructor
  5. @Builder
  6. public class BuilderTest {
  7. private Integer code;
  8. @Builder.default
  9. private String name="";
  10. }

加上@NoArgsConstructor注解之后,你发现new对象的时候,红色波浪线没了。

但是编译的时候,你会发现错误依然在。依然在...

问题还是处在@Builder上面。

这个是为什么呢?

因为默认生成一个全参的构造函数。

但是使用了@NoArgsConstructor之后,全参构造函数没了。这样在编译的时候,如果加了@Builder的话会直接抛出”无法将类 BuilderTest中的构造器BuilderTest应用到给定类型“异常

 所以,在这里你需要成对的使用ArgsConstructor注解,也就是@NoArgsConstructor和@AllArgsConstructor都要加上

  1. import lombok.Builder;
  2. import lombok.Data;
  3. @Data
  4. @NoArgsConstructor
  5. @AllArgsConstructor
  6. @Builder
  7. public class BuilderTest {
  8. private Integer code;
  9. @Builder.default
  10. private String name="";
  11. }

@AllArgsConstructor注解

这个注解的意思就是构造一个全参的构造函数。

为什么要加上@Builder注解和@Builder.Default注解?

我们先看下在@Builder下,代码编译后做了哪些改动。

@Builder详解

测试代码

先看下最简单的@Builder。@Builder使用的是Builder模式,Builder模式不熟悉的可以度娘一下。

  1. import lombok.Builder;
  2. import lombok.Data;
  3. @Builder
  4. public class BuilderTest {
  5. private Integer code;
  6. private String name;
  7. }

@Builder注解编译后代码

  1. public class BuilderTest {
  2. private Integer code;
  3. private String name;
  4. BuilderTest(final Integer code, final String name) {
  5. this.code = code;
  6. this.name = name;
  7. }
  8. public static BuilderTest.BuilderTestBuilder builder() {
  9. return new BuilderTest.BuilderTestBuilder();
  10. }
  11. public static class BuilderTestBuilder {
  12. private Integer code;
  13. private String name;
  14. BuilderTestBuilder() {
  15. }
  16. public BuilderTest.BuilderTestBuilder code(final Integer code) {
  17. this.code = code;
  18. return this;
  19. }
  20. public BuilderTest.BuilderTestBuilder name(final String name) {
  21. this.name = name;
  22. return this;
  23. }
  24. public BuilderTest build() {
  25. return new BuilderTest(this.code, this.name);
  26. }
  27. public String toString() {
  28. return "BuilderTest.BuilderTestBuilder(code=" + this.code + ", name=" + this.name + ")";
  29. }
  30. }
  31. }

代码分析

我们可以看到,编译之后的代码会在原来的代码基础上,增加一个builder方法和对应的一个XXBuilder的静态内部类。

  1. public static BuilderTest.BuilderTestBuilder builder()
  2. public static class BuilderTestBuilder {

同时,在这里默认会生成一个全参的构造函数。但是却缺少了无参构造函数。

所以,如果你直接使用new BuilderTest() 因为没有无参构造函数,所以就会出问题了。

  1. public class BuilderTest {
  2. private Integer code;
  3. private String name;
  4. BuilderTest(final Integer code, final String name) {
  5. this.code = code;
  6. this.name = name;
  7. }
  8. ...

只加上@NoArgsConstructor 后编译class

发现编译直接报上面的异常了。

再加上@AllArgsConstructor编译。

  1. import lombok.AllArgsConstructor;
  2. import lombok.Builder;
  3. import lombok.NoArgsConstructor;
  4. @Builder
  5. @NoArgsConstructor
  6. @AllArgsConstructor
  7. public class BuilderTest {
  8. private Integer code;
  9. //默认值注解
  10. @Builder.Default
  11. private String name="";
  12. }

编译后代码如下

  1. public class BuilderTest {
  2. private Integer code;
  3. private String name;
  4. private static String $default$name() {
  5. return "";
  6. }
  7. public static BuilderTest.BuilderTestBuilder builder() {
  8. return new BuilderTest.BuilderTestBuilder();
  9. }
  10. public BuilderTest() {
  11. this.name = $default$name();
  12. }
  13. public BuilderTest(final Integer code, final String name) {
  14. this.code = code;
  15. this.name = name;
  16. }
  17. public static class BuilderTestBuilder {
  18. private Integer code;
  19. private boolean name$set;
  20. private String name$value;
  21. BuilderTestBuilder() {
  22. }
  23. public BuilderTest.BuilderTestBuilder code(final Integer code) {
  24. this.code = code;
  25. return this;
  26. }
  27. public BuilderTest.BuilderTestBuilder name(final String name) {
  28. this.name$value = name;
  29. this.name$set = true;
  30. return this;
  31. }
  32. public BuilderTest build() {
  33. String name$value = this.name$value;
  34. if (!this.name$set) {
  35. name$value = BuilderTest.$default$name();
  36. }
  37. return new BuilderTest(this.code, name$value);
  38. }
  39. public String toString() {
  40. return "BuilderTest.BuilderTestBuilder(code=" + this.code + ", name$value=" + this.name$value + ")";
  41. }
  42. }
  43. }

错误定位(说明)

我们发现,编译后的代码为有默认值的属性,生成了String $default$name()方法。

使用了@Builder.Default之后,将会在默认无参构造函数中,给属性赋默认值。

  1. private static String $default$name() {
  2. return "";
  3. }
  4. public BuilderTest() {
  5. this.name = $default$name();
  6. }

如果去掉@Builder.Default后,编译结果如下

  1. public class BuilderTest {
  2. private Integer code;
  3. private String name = "";
  4. public static BuilderTest.BuilderTestBuilder builder() {
  5. return new BuilderTest.BuilderTestBuilder();
  6. }
  7. public BuilderTest() {
  8. }
  9. public BuilderTest(final Integer code, final String name) {
  10. this.code = code;
  11. this.name = name;
  12. }
  13. public static class BuilderTestBuilder {
  14. private Integer code;
  15. private String name;
  16. BuilderTestBuilder() {
  17. }
  18. public BuilderTest.BuilderTestBuilder code(final Integer code) {
  19. this.code = code;
  20. return this;
  21. }
  22. public BuilderTest.BuilderTestBuilder name(final String name) {
  23. this.name = name;
  24. return this;
  25. }
  26. public BuilderTest build() {
  27. return new BuilderTest(this.code, this.name);
  28. }
  29. public String toString() {
  30. return "BuilderTest.BuilderTestBuilder(code=" + this.code + ", name=" + this.name + ")";
  31. }
  32. }
  33. }

我们可以看到,如果不使用@Builder.Default的话。

默认的无参构造函数里面是没有赋值操作的。

  1. public BuilderTest() {
  2. }

所以如果你直接new对象的话,不适用@Builder.Default注解,正常情况下是没有默认值的。

你在保存数据到库的时候,当前属性的默认值不会带过去,只会给个null。

数据库没有设置默认值,使用MP进行存储的话,MySQL报insert的存储错误:当前字段没有default Value。

如果需要在DB中存储当前默认值的话,在使用了@Builder注解的类里,需要对类属性字段上加上@Builder.Default注解才能设置默认值。

总结

在类上添加@Builder注解,一般情况下,@NoArgsConstructor和@AllArgsConstructor都是成对出现的。

如果要想设置默认值的话,就必须在属性字段上增加@Builder.Default注解,new对象的时候set默认值。

当然如果你想在所有new对象的时候,使用builder方式来处理的话,那么@NoArgsConstructor和@AllArgsConstructor两个注解你可以不用。

这个个人不太建议,毕竟创建的类就是直接用来new的,如果Builder的话,要是对当前model类进行了修改,那么你需要到处去找使用了new当前对象的builder方法,然后去赋值,虽然前面看起来省了点布料,后面却需要不停的到处打补丁,中间浪费的成本实在太高了,不如一开始就一劳永逸。

这点也比较符合个人的做事风格,宁愿事后睡觉,不愿事中偷懒。毕竟古话说的好,出来混,迟早是要还的,只是时间早晚的事情。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/483031
推荐阅读
相关标签
  

闽ICP备14008679号