lombok @Builder(toBuilder = true) 在子 class 的构造函数上使用时出现编译错误

lombok @Builder(toBuilder = true) compilation error when used on constructor of a sub class

我的代码如下

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;
        }

    }
}

如上所示,我正在尝试在子 class.

上使用 @Builder(toBuilder = true)

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

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

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

问题是因为 toBuilder 方法在 SubClass 中的实现方式:

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

而不是 this.foo 应该是 super.foo,并且代码可以编译。在这种情况下访问 super.foo 是可能的,因为 SubClassSuperClass 的内部 class,否则,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,答案已更新为该信息。

当属性 toBuilder 在注释 @Builder 中设置为 true。方法returnsSubClassBuilderclass。这是 toBuilder 方法的样子,

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

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

错误:java:foo 在 test.lombok.SuperClass

中具有私有访问权限

据我所知,这是一个 Lombok 错误。有三种方法,如何访问 foo 并且只有其中一种有效:

  • 普通 foo 导致 "Cannot make a static reference to the non-static field foo"
  • Lombok 使用的
  • this.foo 导致 "The field SuperClass.foo is not visible"
  • super.foo 有效!

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

从 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)