【问题标题】:lombok @Builder(toBuilder = true) compilation error when used on constructor of a sub classlombok @Builder(toBuilder = true) 在子类的构造函数上使用时出现编译错误
【发布时间】:2017-09-29 03:29:37
【问题描述】:

我的代码如下

package test.lombok;

import lombok.*;

@AllArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public class SuperClass {

    private int foo;

    @Getter
    public static class SubClass extends SuperClass {

        private int bar;

        @Builder(toBuilder = true)
        private SubClass(int foo, int bar) {
            super(foo);
            this.bar = bar;
        }

    }
}

如上所示,我正在尝试在子类上使用@Builder(toBuilder = true)。

toBuilder设置为false时,完全没有问题。

但是当我设置 toBuilder = true 时,出现编译错误“Error:java: foo has private access in test.lombok.SuperClass”。

我想知道为什么会发生这种情况以及如何解决这个问题。

【问题讨论】:

  • 恕我直言,这是一个 Lombok 错误。假设I'm right,你会提交an issue吗?
  • 当然。我已经发布了一个问题#1488

标签: java lombok


【解决方案1】:

当属性 toBuilder 设置为 true 时,Lombok 尝试在 SubClass 中创建 toBuilder 方法 在注释 @Builder 中。该方法返回 SubClassBuilder 类。这是 toBuilder 方法的样子,

public SuperClass.SubClass.SubClassBuilder toBuilder() {
    return (new SuperClass.SubClass.SubClassBuilder())
                    .foo(this.foo).bar(this.bar);
}

如您所见,toBuilder 方法尝试直接访问 foo 属性,而不是通过方法 getFoo。由于 foo 是私有的并且属于父类 SuperClass,因此您会收到以下错误:

错误:java: foo 在 test.lombok.SuperClass 中有私有访问权限

【讨论】:

    【解决方案2】:

    问题在于toBuilder方法在SubClass中是如何实现的:

    public SuperClass.SubClass.SubClassBuilder toBuilder() {
        return (new SuperClass.SubClass.SubClassBuilder()).foo(this.foo).bar(this.bar);
    }
    

    应该是super.foo,而不是this.foo,并且代码会编译。在这种情况下可以访问super.foo,因为SubClassSuperClass 的内部类,否则Java 也会禁止super.foo

    如果你想自己查看lombok生成的代码,将foo声明为public,然后编译,然后delombok(或反编译),你会看到这样的代码(然后将属性更改为private,看看在哪里发生错误):

    import java.beans.ConstructorProperties;
    
    public class SuperClass {
        public int foo;
    
        @ConstructorProperties({"foo"})
        protected SuperClass(int foo) {
            this.foo = foo;
        }
    
        public int getFoo() {
            return this.foo;
        }
    
        public static class SubClass extends SuperClass {
            private int bar;
    
            private SubClass(int foo, int bar) {
                super(foo);
                this.bar = bar;
            }
    
            public static SuperClass.SubClass.SubClassBuilder builder() {
                return new SuperClass.SubClass.SubClassBuilder();
            }
    
            public SuperClass.SubClass.SubClassBuilder toBuilder() {
                return (new SuperClass.SubClass.SubClassBuilder()).foo(this.foo).bar(this.bar);
            }
    
            public int getBar() {
                return this.bar;
            }
    
            public static class SubClassBuilder {
                private int foo;
                private int bar;
    
                SubClassBuilder() {
                }
    
                public SuperClass.SubClass.SubClassBuilder foo(int foo) {
                    this.foo = foo;
                    return this;
                }
    
                public SuperClass.SubClass.SubClassBuilder bar(int bar) {
                    this.bar = bar;
                    return this;
                }
    
                public SuperClass.SubClass build() {
                    return new SuperClass.SubClass(this.foo, this.bar);
                }
    
                public String toString() {
                    return "SuperClass.SubClass.SubClassBuilder(foo=" + this.foo + ", bar=" + this.bar + ")";
                }
            }
        }
    }
    

    编辑:感谢@maaartinus 将我指向super.foo,答案已更新为该信息。

    【讨论】:

    • 谢谢你,蒙德金。很详细的解释!所以我想没有办法让lombok生成子类的toBuilder()?是否可以在 toBuilder() 中调用 getFoo() 而不是 this.foo ?
    • 一种解决方案是将foo 声明为受保护,这样您就可以从子类内部访问它。否则,我不知道有什么方法可以告诉 lombok 使用访问器方法。
    • @MondKin 我猜,您错过了一个更好的解决方案:使用super.foo 作为在同一源文件中声明的字段 可访问的。显然,这应该在 Lombok 中修复。
    • @maaartinus 你说得对,我没有注意到在 lombok 侧用super 替换this 可以解决问题。
    【解决方案3】:

    AFAICT 这是一个龙目岛错误。共有三种方式,如何访问foo,只有一种有效:

    • plain foo 导致“无法对非静态字段 foo 进行静态引用”
    • Lombok 使用的this.foo 导致“SuperClass.foo 字段不可见”
    • super.foo 工作!

    AFAIK 在同一源文件中声明的所有内容都可以以某种方式访问,但找到正确的表达式可能会很棘手。

    【讨论】:

      【解决方案4】:

      从 Lombok 1.18.12 开始,您可以使用新的实验性功能@SuperBuilder

      支持toBuilder

      import lombok.*;
      import lombok.experimental.SuperBuilder;
      
      @AllArgsConstructor(access = AccessLevel.PROTECTED)
      @Getter
      @ToString // For demonstration purposes only; only used in the main method.
      @SuperBuilder(toBuilder = true)
      public class SuperClass {
      
          private int foo;
      
          @Getter
          @ToString(callSuper = true) // For demonstration purposes only; only used in the main method.
          @SuperBuilder(toBuilder = true)
          public static class SubClass extends SuperClass {
      
              private int bar;
      
              private SubClass(int foo, int bar) {
                  super(foo);
                  this.bar = bar;
              }
          }
      
          public static void main(String[] argv) {
              SubClass sc = SubClass.builder()
                      .foo(1)
                      .bar(2)
                      .build();
              System.out.println(sc);
          }
      }
      

      打印:

      SuperClass.SubClass(super=SuperClass(foo=1), bar=2)
      

      【讨论】:

        猜你喜欢
        • 2020-08-25
        • 1970-01-01
        • 1970-01-01
        • 2011-03-05
        • 1970-01-01
        • 2019-06-09
        • 1970-01-01
        • 1970-01-01
        • 2016-03-18
        相关资源
        最近更新 更多