mirror of
https://github.com/tiennm99/lombok.git
synced 2026-10-14 18:18:48 +00:00
support @Builder.Default
This commit is contained in:
1 parent
51c0c40ac4
commit
d11263a6c6
8 files changed
+290
-42
No files matched your search
@@ -31,6 +31,7 @@ import lombok.core.AnnotationValues;
|
||||
import lombok.core.HandlerPriority;
|
||||
import lombok.eclipse.EclipseAnnotationHandler;
|
||||
import lombok.eclipse.EclipseNode;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
@ProviderFor(EclipseAnnotationHandler.class)
|
||||
@HandlerPriority(-1025) //HandleBuilder's level, minus one.
|
||||
@@ -39,8 +40,9 @@ public class HandleBuilderDefault extends EclipseAnnotationHandler<Builder.Defau
|
||||
EclipseNode annotatedField = annotationNode.up();
|
||||
if (annotatedField.getKind() != Kind.FIELD) return;
|
||||
EclipseNode classWithAnnotatedField = annotatedField.up();
|
||||
if (!hasAnnotation(Builder.class, classWithAnnotatedField) && !hasAnnotation("lombok.experimental.Builder", classWithAnnotatedField)) {
|
||||
annotationNode.addWarning("@Builder.Default requires @Builder on the class for it to mean anything.");
|
||||
if (!hasAnnotation(Builder.class, classWithAnnotatedField) && !hasAnnotation("lombok.experimental.Builder", classWithAnnotatedField)
|
||||
&& !hasAnnotation(SuperBuilder.class, classWithAnnotatedField)) {
|
||||
annotationNode.addWarning("@Builder.Default requires @Builder or @SuperBuilder on the class for it to mean anything.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,7 @@ import org.eclipse.jdt.internal.compiler.ast.Expression;
|
||||
import org.eclipse.jdt.internal.compiler.ast.FalseLiteral;
|
||||
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.FieldReference;
|
||||
import org.eclipse.jdt.internal.compiler.ast.IfStatement;
|
||||
import org.eclipse.jdt.internal.compiler.ast.MessageSend;
|
||||
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
|
||||
import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference;
|
||||
@@ -93,9 +94,8 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
|
||||
|
||||
private static final char[] CLEAN_FIELD_NAME = "$lombokUnclean".toCharArray();
|
||||
private static final char[] CLEAN_METHOD_NAME = "$lombokClean".toCharArray();
|
||||
private static final char[] DEFAULT_PREFIX = {'$', 'd', 'e', 'f', 'a', 'u', 'l', 't', '$'};
|
||||
private static final char[] SET_PREFIX = {'$', 's', 'e', 't'};
|
||||
private static final String SELF_METHOD = "self";
|
||||
private static final char[] SET_PREFIX = "$set".toCharArray();
|
||||
private static final char[] SELF_METHOD_NAME = "self".toCharArray();
|
||||
|
||||
private static final AbstractMethodDeclaration[] EMPTY_METHODS = {};
|
||||
|
||||
@@ -103,7 +103,6 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
|
||||
TypeReference type;
|
||||
char[] rawName;
|
||||
char[] name;
|
||||
char[] nameOfDefaultProvider;
|
||||
char[] nameOfSetFlag;
|
||||
SingularData singularData;
|
||||
ObtainVia obtainVia;
|
||||
@@ -185,13 +184,16 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
|
||||
}
|
||||
|
||||
if (isDefault != null) {
|
||||
bfd.nameOfDefaultProvider = prefixWith(DEFAULT_PREFIX, bfd.name);
|
||||
bfd.nameOfSetFlag = prefixWith(bfd.name, SET_PREFIX);
|
||||
|
||||
MethodDeclaration md = HandleBuilder.generateDefaultProvider(bfd.nameOfDefaultProvider, td.typeParameters, fieldNode, ast);
|
||||
if (md != null) {
|
||||
injectMethod(tdParent, md);
|
||||
}
|
||||
// The @Builder annotation removes the initializing expression on the field and moves
|
||||
// it to a method called "$default$FIELDNAME". This method is then called upon building.
|
||||
// We do NOT do this, because this is unexpected and may lead to bugs when using other
|
||||
// constructors (see, e.g., issue #1347).
|
||||
// Instead, we keep the init expression and only set a new value in the builder-based
|
||||
// constructor if it was set in the builder. Drawback is that the init expression is
|
||||
// always executed, even if it was unnecessary because its value is overwritten by the
|
||||
// builder.
|
||||
// TODO: Once the issue is resolved in @Builder, we can adapt the solution here.
|
||||
}
|
||||
addObtainVia(bfd, fieldNode);
|
||||
builderFields.add(bfd);
|
||||
@@ -481,9 +483,17 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
|
||||
long[] positions = new long[] {p, p};
|
||||
assignmentExpr = new QualifiedNameReference(variableInBuilder, positions, s, e);
|
||||
}
|
||||
|
||||
Assignment assignment = new Assignment(thisX, assignmentExpr, (int) p);
|
||||
Statement assignment = new Assignment(thisX, assignmentExpr, (int) p);
|
||||
|
||||
// In case of @Builder.Default, only set the value if it really was set in the builder.
|
||||
if (fieldNode.nameOfSetFlag != null) {
|
||||
char[][] variableInBuilder = new char[][] {"b".toCharArray(), fieldNode.nameOfSetFlag};
|
||||
long[] positions = new long[] {p, p};
|
||||
QualifiedNameReference builderRef = new QualifiedNameReference(variableInBuilder, positions, s, e);
|
||||
assignment = new IfStatement(builderRef, assignment, s, e);
|
||||
}
|
||||
statements.add(assignment);
|
||||
|
||||
Annotation[] nonNulls = findAnnotations((FieldDeclaration)fieldNode.originalFieldNode.get(), NON_NULL_PATTERN);
|
||||
if (nonNulls.length != 0) {
|
||||
Statement nullCheck = generateNullCheck((FieldDeclaration)fieldNode.originalFieldNode.get(), sourceNode);
|
||||
@@ -527,7 +537,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
|
||||
|
||||
private MethodDeclaration generateAbstractSelfMethod(EclipseNode tdParent, boolean override, String builderGenericName) {
|
||||
MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) tdParent.top().get()).compilationResult);
|
||||
out.selector = SELF_METHOD.toCharArray();
|
||||
out.selector = SELF_METHOD_NAME;
|
||||
out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
out.modifiers = ClassFileConstants.AccAbstract | ClassFileConstants.AccProtected | ExtraCompilerModifiers.AccSemicolonBody;
|
||||
if (override) {
|
||||
@@ -539,7 +549,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
|
||||
|
||||
private MethodDeclaration generateSelfMethod(EclipseNode builderImplType) {
|
||||
MethodDeclaration out = new MethodDeclaration(((CompilationUnitDeclaration) builderImplType.top().get()).compilationResult);
|
||||
out.selector = SELF_METHOD.toCharArray();
|
||||
out.selector = SELF_METHOD_NAME;
|
||||
out.bits |= ECLIPSE_DO_NOT_TOUCH_FLAG;
|
||||
out.modifiers = ClassFileConstants.AccProtected;
|
||||
out.annotations = new Annotation[] {makeMarkerAnnotation(TypeConstants.JAVA_LANG_OVERRIDE, builderImplType.get())};
|
||||
@@ -665,7 +675,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler<SuperBuilder> {
|
||||
@Override public ReturnStatement get() {
|
||||
MessageSend returnCall = new MessageSend();
|
||||
returnCall.receiver = ThisReference.implicitThis();
|
||||
returnCall.selector = SELF_METHOD.toCharArray();
|
||||
returnCall.selector = SELF_METHOD_NAME;
|
||||
return new ReturnStatement(returnCall, 0, 0);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -31,6 +31,7 @@ import lombok.Builder;
|
||||
import lombok.core.AST.Kind;
|
||||
import lombok.core.AnnotationValues;
|
||||
import lombok.core.HandlerPriority;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import lombok.javac.JavacAnnotationHandler;
|
||||
import lombok.javac.JavacNode;
|
||||
|
||||
@@ -41,8 +42,9 @@ public class HandleBuilderDefault extends JavacAnnotationHandler<Builder.Default
|
||||
JavacNode annotatedField = annotationNode.up();
|
||||
if (annotatedField.getKind() != Kind.FIELD) return;
|
||||
JavacNode classWithAnnotatedField = annotatedField.up();
|
||||
if (!hasAnnotation(Builder.class, classWithAnnotatedField) && !hasAnnotation("lombok.experimental.Builder", classWithAnnotatedField)) {
|
||||
annotationNode.addWarning("@Builder.Default requires @Builder on the class for it to mean anything.");
|
||||
if (!hasAnnotation(Builder.class, classWithAnnotatedField) && !hasAnnotation("lombok.experimental.Builder", classWithAnnotatedField)
|
||||
&& !hasAnnotation(SuperBuilder.class, classWithAnnotatedField)) {
|
||||
annotationNode.addWarning("@Builder.Default requires @Builder or @SuperBuilder on the class for it to mean anything.");
|
||||
deleteAnnotationIfNeccessary(annotationNode, Builder.Default.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ import com.sun.tools.javac.tree.JCTree.JCClassDecl;
|
||||
import com.sun.tools.javac.tree.JCTree.JCExpression;
|
||||
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
|
||||
import com.sun.tools.javac.tree.JCTree.JCIdent;
|
||||
import com.sun.tools.javac.tree.JCTree.JCIf;
|
||||
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
|
||||
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
|
||||
import com.sun.tools.javac.tree.JCTree.JCModifiers;
|
||||
@@ -82,7 +83,6 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
|
||||
JCExpression type;
|
||||
Name rawName;
|
||||
Name name;
|
||||
Name nameOfDefaultProvider;
|
||||
Name nameOfSetFlag;
|
||||
SingularData singularData;
|
||||
ObtainVia obtainVia;
|
||||
@@ -164,13 +164,16 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
|
||||
}
|
||||
|
||||
if (isDefault != null) {
|
||||
bfd.nameOfDefaultProvider = tdParent.toName("$default$" + bfd.name);
|
||||
bfd.nameOfSetFlag = tdParent.toName(bfd.name + "$set");
|
||||
JCMethodDecl md = generateDefaultProvider(bfd.nameOfDefaultProvider, fieldNode, td.typarams);
|
||||
recursiveSetGeneratedBy(md, ast, annotationNode.getContext());
|
||||
if (md != null) {
|
||||
injectMethod(tdParent, md);
|
||||
}
|
||||
// The @Builder annotation removes the initializing expression on the field and moves
|
||||
// it to a method called "$default$FIELDNAME". This method is then called upon building.
|
||||
// We do NOT do this, because this is unexpected and may lead to bugs when using other
|
||||
// constructors (see, e.g., issue #1347).
|
||||
// Instead, we keep the init expression and only set a new value in the builder-based
|
||||
// constructor if it was set in the builder. Drawback is that the init expression is
|
||||
// always executed, even if it was unnecessary because its value is overwritten by the
|
||||
// builder.
|
||||
// TODO: Once the issue is resolved in @Builder, we can adapt the solution here.
|
||||
}
|
||||
addObtainVia(bfd, fieldNode);
|
||||
builderFields.add(bfd);
|
||||
@@ -435,9 +438,16 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
|
||||
}
|
||||
JCFieldAccess thisX = maker.Select(maker.Ident(typeNode.toName("this")), bfd.rawName);
|
||||
|
||||
JCExpression assign = maker.Assign(thisX, rhs);
|
||||
|
||||
statements.append(maker.Exec(assign));
|
||||
JCStatement assign = maker.Exec(maker.Assign(thisX, rhs));
|
||||
|
||||
// In case of @Builder.Default, only set the value if it really was set in the builder.
|
||||
if (bfd.nameOfSetFlag != null) {
|
||||
JCFieldAccess setField = maker.Select(maker.Ident(builderVariableName), bfd.nameOfSetFlag);
|
||||
JCIf ifSet = maker.If(setField, assign, null);
|
||||
statements.append(ifSet);
|
||||
} else {
|
||||
statements.append(assign);
|
||||
}
|
||||
}
|
||||
|
||||
JCModifiers mods = maker.Modifiers(toJavacModifier(level), List.<JCAnnotation>nil());
|
||||
@@ -575,18 +585,6 @@ public class HandleSuperBuilder extends JavacAnnotationHandler<SuperBuilder> {
|
||||
return maker.MethodDef(maker.Modifiers(Flags.PUBLIC), type.toName("$lombokClean"), maker.Type(Javac.createVoidType(type.getSymbolTable(), CTC_VOID)), List.<JCTypeParameter>nil(), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null);
|
||||
}
|
||||
|
||||
private JCMethodDecl generateDefaultProvider(Name methodName, JavacNode fieldNode, List<JCTypeParameter> params) {
|
||||
JavacTreeMaker maker = fieldNode.getTreeMaker();
|
||||
JCVariableDecl field = (JCVariableDecl) fieldNode.get();
|
||||
|
||||
JCStatement statement = maker.Return(field.init);
|
||||
field.init = null;
|
||||
|
||||
JCBlock body = maker.Block(0, List.<JCStatement>of(statement));
|
||||
int modifiers = Flags.PRIVATE | Flags.STATIC;
|
||||
return maker.MethodDef(maker.Modifiers(modifiers), methodName, cloneType(maker, field.vartype, field, fieldNode.getContext()), copyTypeParams(fieldNode, params), List.<JCVariableDecl>nil(), List.<JCExpression>nil(), body, null);
|
||||
}
|
||||
|
||||
private void generateBuilderFields(JavacNode builderType, java.util.List<BuilderFieldData> builderFields, JCTree source) {
|
||||
int len = builderFields.size();
|
||||
java.util.List<JavacNode> existing = new ArrayList<JavacNode>();
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
import java.util.List;
|
||||
public class SuperBuilderWithDefaults {
|
||||
public static class Parent<N extends Number> {
|
||||
private long millis = System.currentTimeMillis();
|
||||
private N numberField = null;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public static abstract class ParentBuilder<N extends Number, C extends Parent<N>, B extends ParentBuilder<N, C, B>> {
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private boolean millis$set;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private long millis;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private boolean numberField$set;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private N numberField;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected abstract B self();
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public abstract C build();
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public B millis(final long millis) {
|
||||
this.millis = millis;
|
||||
millis$set = true;
|
||||
return self();
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public B numberField(final N numberField) {
|
||||
this.numberField = numberField;
|
||||
numberField$set = true;
|
||||
return self();
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public java.lang.String toString() {
|
||||
return "SuperBuilderWithDefaults.Parent.ParentBuilder(millis=" + this.millis + ", numberField=" + this.numberField + ")";
|
||||
}
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private static final class ParentBuilderImpl<N extends Number> extends ParentBuilder<N, Parent<N>, ParentBuilderImpl<N>> {
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private ParentBuilderImpl() {
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected ParentBuilderImpl self() {
|
||||
return this;
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public Parent<N> build() {
|
||||
return new Parent<N>(this);
|
||||
}
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected Parent(final ParentBuilder<N, ?, ?> b) {
|
||||
if (b.millis$set) this.millis = b.millis;
|
||||
if (b.numberField$set) this.numberField = b.numberField;
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public static <N extends Number> ParentBuilder<N, ?, ?> builder() {
|
||||
return new ParentBuilderImpl<N>();
|
||||
}
|
||||
}
|
||||
public static class Child extends Parent<Integer> {
|
||||
private double doubleField = Math.PI;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public static abstract class ChildBuilder<C extends Child, B extends ChildBuilder<C, B>> extends Parent.ParentBuilder<Integer, C, B> {
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private boolean doubleField$set;
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private double doubleField;
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected abstract B self();
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public abstract C build();
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public B doubleField(final double doubleField) {
|
||||
this.doubleField = doubleField;
|
||||
doubleField$set = true;
|
||||
return self();
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public java.lang.String toString() {
|
||||
return "SuperBuilderWithDefaults.Child.ChildBuilder(super=" + super.toString() + ", doubleField=" + this.doubleField + ")";
|
||||
}
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private static final class ChildBuilderImpl extends ChildBuilder<Child, ChildBuilderImpl> {
|
||||
@java.lang.SuppressWarnings("all")
|
||||
private ChildBuilderImpl() {
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected ChildBuilderImpl self() {
|
||||
return this;
|
||||
}
|
||||
@java.lang.Override
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public Child build() {
|
||||
return new Child(this);
|
||||
}
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
protected Child(final ChildBuilder<?, ?> b) {
|
||||
super(b);
|
||||
if (b.doubleField$set) this.doubleField = b.doubleField;
|
||||
}
|
||||
@java.lang.SuppressWarnings("all")
|
||||
public static ChildBuilder<?, ?> builder() {
|
||||
return new ChildBuilderImpl();
|
||||
}
|
||||
}
|
||||
public static void test() {
|
||||
Child x = Child.builder().doubleField(0.1).numberField(5).millis(1234567890L).build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
import java.util.List;
|
||||
public class SuperBuilderWithDefaults {
|
||||
public static @lombok.experimental.SuperBuilder class Parent<N extends Number> {
|
||||
public static abstract @java.lang.SuppressWarnings("all") class ParentBuilder<N extends Number, C extends Parent<N>, B extends ParentBuilder<N, C, B>> {
|
||||
private @java.lang.SuppressWarnings("all") long millis;
|
||||
private @java.lang.SuppressWarnings("all") boolean millis$set;
|
||||
private @java.lang.SuppressWarnings("all") N numberField;
|
||||
private @java.lang.SuppressWarnings("all") boolean numberField$set;
|
||||
public ParentBuilder() {
|
||||
super();
|
||||
}
|
||||
protected abstract @java.lang.SuppressWarnings("all") B self();
|
||||
public abstract @java.lang.SuppressWarnings("all") C build();
|
||||
public @java.lang.SuppressWarnings("all") B millis(final long millis) {
|
||||
this.millis = millis;
|
||||
millis$set = true;
|
||||
return self();
|
||||
}
|
||||
public @java.lang.SuppressWarnings("all") B numberField(final N numberField) {
|
||||
this.numberField = numberField;
|
||||
numberField$set = true;
|
||||
return self();
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
|
||||
return (((("SuperBuilderWithDefaults.Parent.ParentBuilder(millis=" + this.millis) + ", numberField=") + this.numberField) + ")");
|
||||
}
|
||||
}
|
||||
private static final @java.lang.SuppressWarnings("all") class ParentBuilderImpl<N extends Number> extends ParentBuilder<N, Parent<N>, ParentBuilderImpl<N>> {
|
||||
private ParentBuilderImpl() {
|
||||
super();
|
||||
}
|
||||
protected @java.lang.Override @java.lang.SuppressWarnings("all") ParentBuilderImpl self() {
|
||||
return this;
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") Parent<N> build() {
|
||||
return new Parent<N>(this);
|
||||
}
|
||||
}
|
||||
private @lombok.Builder.Default long millis = System.currentTimeMillis();
|
||||
private @lombok.Builder.Default N numberField = null;
|
||||
protected @java.lang.SuppressWarnings("all") Parent(final ParentBuilder<N, ?, ?> b) {
|
||||
super();
|
||||
if (b.millis$set)
|
||||
this.millis = b.millis;
|
||||
if (b.numberField$set)
|
||||
this.numberField = b.numberField;
|
||||
}
|
||||
public static @java.lang.SuppressWarnings("all") <N extends Number>ParentBuilder<N, ?, ?> builder() {
|
||||
return new ParentBuilderImpl<N>();
|
||||
}
|
||||
}
|
||||
public static @lombok.experimental.SuperBuilder class Child extends Parent<Integer> {
|
||||
public static abstract @java.lang.SuppressWarnings("all") class ChildBuilder<C extends Child, B extends ChildBuilder<C, B>> extends Parent.ParentBuilder<Integer, C, B> {
|
||||
private @java.lang.SuppressWarnings("all") double doubleField;
|
||||
private @java.lang.SuppressWarnings("all") boolean doubleField$set;
|
||||
public ChildBuilder() {
|
||||
super();
|
||||
}
|
||||
protected abstract @java.lang.Override @java.lang.SuppressWarnings("all") B self();
|
||||
public abstract @java.lang.Override @java.lang.SuppressWarnings("all") C build();
|
||||
public @java.lang.SuppressWarnings("all") B doubleField(final double doubleField) {
|
||||
this.doubleField = doubleField;
|
||||
doubleField$set = true;
|
||||
return self();
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() {
|
||||
return (((("SuperBuilderWithDefaults.Child.ChildBuilder(super=" + super.toString()) + ", doubleField=") + this.doubleField) + ")");
|
||||
}
|
||||
}
|
||||
private static final @java.lang.SuppressWarnings("all") class ChildBuilderImpl extends ChildBuilder<Child, ChildBuilderImpl> {
|
||||
private ChildBuilderImpl() {
|
||||
super();
|
||||
}
|
||||
protected @java.lang.Override @java.lang.SuppressWarnings("all") ChildBuilderImpl self() {
|
||||
return this;
|
||||
}
|
||||
public @java.lang.Override @java.lang.SuppressWarnings("all") Child build() {
|
||||
return new Child(this);
|
||||
}
|
||||
}
|
||||
private @lombok.Builder.Default double doubleField = Math.PI;
|
||||
protected @java.lang.SuppressWarnings("all") Child(final ChildBuilder<?, ?> b) {
|
||||
super(b);
|
||||
if (b.doubleField$set)
|
||||
this.doubleField = b.doubleField;
|
||||
}
|
||||
public static @java.lang.SuppressWarnings("all") ChildBuilder<?, ?> builder() {
|
||||
return new ChildBuilderImpl();
|
||||
}
|
||||
}
|
||||
public SuperBuilderWithDefaults() {
|
||||
super();
|
||||
}
|
||||
public static void test() {
|
||||
Child x = Child.builder().doubleField(0.1).numberField(5).millis(1234567890L).build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import java.util.List;
|
||||
|
||||
public class SuperBuilderWithDefaults {
|
||||
@lombok.experimental.SuperBuilder
|
||||
public static class Parent<N extends Number> {
|
||||
@lombok.Builder.Default private long millis = System.currentTimeMillis();
|
||||
@lombok.Builder.Default private N numberField = null;
|
||||
}
|
||||
|
||||
@lombok.experimental.SuperBuilder
|
||||
public static class Child extends Parent<Integer> {
|
||||
@lombok.Builder.Default private double doubleField = Math.PI;
|
||||
}
|
||||
|
||||
public static void test() {
|
||||
Child x = Child.builder().doubleField(0.1).numberField(5).millis(1234567890L).build();
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,8 @@
|
||||
Therefore, a <code>@SuperBuilder</code> must extend the <code>@SuperBuilder</code> of the superclass in order to include those methods.
|
||||
Furthermore, the generated builder code heavily relies on generics to avoid class casting when using the builder.
|
||||
<code>@SuperBuilder</code> generates a private constructor on the class that takes a builder instances as a parameter. This constructor sets the fields of the new instance to the values from the builder.
|
||||
</p><p>
|
||||
<code>@SuperBuilder</code> is not compatible with <code>@Builder</code>.
|
||||
</p><p>
|
||||
To ensure type-safety, <code>@SuperBuilder</code> generates two inner builder classes for each annotated class, one abstract and one concrete class named <code><em>Foobar</em>Builder</code> and <code><em>Foobar</em>BuilderImpl</code> (where <em>Foobar</em> is the name of the annotated class).
|
||||
</p><p>
|
||||
@@ -43,7 +45,7 @@
|
||||
|
||||
<@f.confKeys>
|
||||
<dt>
|
||||
<code>lombok.builder.flagUsage</code> = [<code>warning</code> | <code>error</code>] (default: not set)
|
||||
<code>lombok.superBuilder.flagUsage</code> = [<code>warning</code> | <code>error</code>] (default: not set)
|
||||
</dt><dd>
|
||||
Lombok will flag any usage of <code>@SuperBuilder</code> as a warning or error if configured.
|
||||
</dd><dt>
|
||||
|
||||
Reference in new issue
Block a user