My code is as followd
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;
}
}
}
As showed above, I'm trying to use @Builder(toBuilder = true) on a sub class.
When toBuilder set to false, there is no problem at all.
But when I set toBuilder = true, I got an compilation error "Error:java: foo has private access in test.lombok.SuperClass".
I'm wondering why does this happen and how to fix this.
Lombok tries to create toBuilder method in SubClass when the attribute toBuilder is set to true in annotation @Builder. The method returns the SubClassBuilder class. Here is the what the toBuilder method would look like,
public SuperClass.SubClass.SubClassBuilder toBuilder() {
return (new SuperClass.SubClass.SubClassBuilder())
.foo(this.foo).bar(this.bar);
}
As you notice, toBuilder method tries to access foo attribute directly and not by method getFoo. Since foo is private and belongs to the parent class, SuperClass, you get the following error:
Error:java: foo has private access in test.lombok.SuperClass
The problem is because of how the toBuilder
method is implemented in SubClass
:
public SuperClass.SubClass.SubClassBuilder toBuilder() {
return (new SuperClass.SubClass.SubClassBuilder()).foo(this.foo).bar(this.bar);
}
Instead of this.foo
it should be super.foo
, and the code would compile. Accessing super.foo
is possible in this case because SubClass
is an inner class of the SuperClass
, otherwise, Java would disallow super.foo
too.
If you want to see the code generated by lombok by for yourself, declare foo
as public, then compile, then delombok (or decompile) and you will see code like this (then change the property to private to see where the error occurs):
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 + ")";
}
}
}
}
EDIT: Thanks to @maaartinus for pointing me to super.foo
, the answer is updated with that info.
AFAICT this is a Lombok bug. There are three ways, how to access foo
and only one of them works:
foo
leads to "Cannot make a static reference to the non-static field foo"this.foo
as used by Lombok leads to "The field SuperClass.foo is not visible"super.foo
works!AFAIK everything declared in the same source file is accessible somehow, but finding the proper expression might be tricky.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With