From e2fc6fa56433e5a62939bc2a3d92a4372539f3db Mon Sep 17 00:00:00 2001 From: Jan Rieke Date: Mon, 4 Jun 2018 17:52:38 +0200 Subject: SuperBuilder support for abstract classes --- .../eclipse/handlers/HandleSuperBuilder.java | 5 + .../lombok/javac/handlers/HandleSuperBuilder.java | 61 +++++----- .../after-delombok/SuperBuilderAbstract.java | 129 +++++++++++++++++++++ .../resource/after-ecj/SuperBuilderAbstract.java | 102 ++++++++++++++++ .../resource/before/SuperBuilderAbstract.java | 20 ++++ 5 files changed, 291 insertions(+), 26 deletions(-) create mode 100644 test/transform/resource/after-delombok/SuperBuilderAbstract.java create mode 100644 test/transform/resource/after-ecj/SuperBuilderAbstract.java create mode 100644 test/transform/resource/before/SuperBuilderAbstract.java diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index 3a92da4a..1100cbf0 100644 --- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java @@ -333,6 +333,11 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { injectMethod(builderType, generateCleanMethod(builderFields, builderType, ast)); } + if ((td.modifiers & ClassFileConstants.AccAbstract) != 0) { + // Abstract classes to not get the Builder implementation nor the builder() method. + return; + } + // Create the builder implementation class. EclipseNode builderImplType = findInnerClass(tdParent, builderImplClassName); if (builderImplType == null) { diff --git a/src/core/lombok/javac/handlers/HandleSuperBuilder.java b/src/core/lombok/javac/handlers/HandleSuperBuilder.java index beee47a9..1835bd48 100644 --- a/src/core/lombok/javac/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/javac/handlers/HandleSuperBuilder.java @@ -282,42 +282,51 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { if (addCleaning) { injectMethod(builderType, generateCleanMethod(builderFields, builderType, ast)); } + + recursiveSetGeneratedBy(builderType.get(), ast, annotationNode.getContext()); - // Create the builder implementation class. - JavacNode builderImplType = findInnerClass(tdParent, builderImplClassName); - if (builderImplType == null) { - builderImplType = generateBuilderImplClass(annotationNode, tdParent, builderImplClassName, builderClassName, typeParams, ast); - } else { - annotationNode.addError("@SuperBuilder does not support customized builders. Use @Builder instead."); - return; - } + if ((td.mods.flags & Flags.ABSTRACT) == 0) { + // Only non-abstract classes get the Builder implementation. - // Create a simple constructor for the BuilderImpl class. - JCMethodDecl cd = HandleConstructor.createConstructor(AccessLevel.PRIVATE, List.nil(), builderImplType, List.nil(), false, annotationNode); - if (cd != null) { - injectMethod(builderImplType, cd); - } + // Create the builder implementation class. + JavacNode builderImplType = findInnerClass(tdParent, builderImplClassName); + if (builderImplType == null) { + builderImplType = generateBuilderImplClass(annotationNode, tdParent, builderImplClassName, builderClassName, typeParams, ast); + } else { + annotationNode.addError("@SuperBuilder does not support customized builders. Use @Builder instead."); + return; + } + + // Create a simple constructor for the BuilderImpl class. + JCMethodDecl cd = HandleConstructor.createConstructor(AccessLevel.PRIVATE, List.nil(), builderImplType, List.nil(), false, annotationNode); + if (cd != null) { + injectMethod(builderImplType, cd); + } - // Create the self() and build() methods in the BuilderImpl. - injectMethod(builderImplType, generateSelfMethod(builderImplType)); - injectMethod(builderImplType, generateBuildMethod(buildMethodName, returnType, builderImplType, thrownExceptions)); + // Create the self() and build() methods in the BuilderImpl. + injectMethod(builderImplType, generateSelfMethod(builderImplType)); + injectMethod(builderImplType, generateBuildMethod(buildMethodName, returnType, builderImplType, thrownExceptions)); + + recursiveSetGeneratedBy(builderImplType.get(), ast, annotationNode.getContext()); + } // Generate a constructor in the annotated class that takes a builder as argument. generateBuilderBasedConstructor(tdParent, typeParams, builderFields, annotationNode, builderClassName, superclassBuilderClassExpression != null); - // Add the builder() method to the annotated class. - // Allow users to specify their own builder() methods, e.g., to provide default values. - if (methodExists(builderMethodName, tdParent, -1) == MemberExistsResult.NOT_EXISTS) { - JCMethodDecl builderMethod = generateBuilderMethod(builderMethodName, builderClassName, builderImplClassName, annotationNode, tdParent, typeParams); - recursiveSetGeneratedBy(builderMethod, ast, annotationNode.getContext()); - if (builderMethod != null) { - injectMethod(tdParent, builderMethod); + if ((td.mods.flags & Flags.ABSTRACT) == 0) { + // Only non-abstract classes get the Builder implementation and the builder() method. + + // Add the builder() method to the annotated class. + // Allow users to specify their own builder() methods, e.g., to provide default values. + if (methodExists(builderMethodName, tdParent, -1) == MemberExistsResult.NOT_EXISTS) { + JCMethodDecl builderMethod = generateBuilderMethod(builderMethodName, builderClassName, builderImplClassName, annotationNode, tdParent, typeParams); + recursiveSetGeneratedBy(builderMethod, ast, annotationNode.getContext()); + if (builderMethod != null) { + injectMethod(tdParent, builderMethod); + } } } - - recursiveSetGeneratedBy(builderType.get(), ast, annotationNode.getContext()); - recursiveSetGeneratedBy(builderImplType.get(), ast, annotationNode.getContext()); } /** diff --git a/test/transform/resource/after-delombok/SuperBuilderAbstract.java b/test/transform/resource/after-delombok/SuperBuilderAbstract.java new file mode 100644 index 00000000..d1e82c27 --- /dev/null +++ b/test/transform/resource/after-delombok/SuperBuilderAbstract.java @@ -0,0 +1,129 @@ +public class SuperBuilderAbstract { + public static class Parent { + int parentField; + @java.lang.SuppressWarnings("all") + public static abstract class ParentBuilder> { + @java.lang.SuppressWarnings("all") + private int parentField; + @java.lang.SuppressWarnings("all") + protected abstract B self(); + @java.lang.SuppressWarnings("all") + public abstract C build(); + @java.lang.SuppressWarnings("all") + public B parentField(final int parentField) { + this.parentField = parentField; + return self(); + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "SuperBuilderAbstract.Parent.ParentBuilder(parentField=" + this.parentField + ")"; + } + } + @java.lang.SuppressWarnings("all") + private static final class ParentBuilderImpl extends ParentBuilder { + @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 build() { + return new Parent(this); + } + } + @java.lang.SuppressWarnings("all") + protected Parent(final ParentBuilder b) { + this.parentField = b.parentField; + } + @java.lang.SuppressWarnings("all") + public static ParentBuilder builder() { + return new ParentBuilderImpl(); + } + } + public static abstract class Child extends Parent { + double childField; + @java.lang.SuppressWarnings("all") + public static abstract class ChildBuilder> extends Parent.ParentBuilder { + @java.lang.SuppressWarnings("all") + private double childField; + @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 childField(final double childField) { + this.childField = childField; + return self(); + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "SuperBuilderAbstract.Child.ChildBuilder(super=" + super.toString() + ", childField=" + this.childField + ")"; + } + } + @java.lang.SuppressWarnings("all") + protected Child(final ChildBuilder b) { + super(b); + this.childField = b.childField; + } + } + public static class GrandChild extends Child { + String grandChildField; + @java.lang.SuppressWarnings("all") + public static abstract class GrandChildBuilder> extends Child.ChildBuilder { + @java.lang.SuppressWarnings("all") + private String grandChildField; + @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 grandChildField(final String grandChildField) { + this.grandChildField = grandChildField; + return self(); + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "SuperBuilderAbstract.GrandChild.GrandChildBuilder(super=" + super.toString() + ", grandChildField=" + this.grandChildField + ")"; + } + } + @java.lang.SuppressWarnings("all") + private static final class GrandChildBuilderImpl extends GrandChildBuilder { + @java.lang.SuppressWarnings("all") + private GrandChildBuilderImpl() { + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + protected GrandChildBuilderImpl self() { + return this; + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public GrandChild build() { + return new GrandChild(this); + } + } + @java.lang.SuppressWarnings("all") + protected GrandChild(final GrandChildBuilder b) { + super(b); + this.grandChildField = b.grandChildField; + } + @java.lang.SuppressWarnings("all") + public static GrandChildBuilder builder() { + return new GrandChildBuilderImpl(); + } + } + public static void test() { + GrandChild x = GrandChild.builder().grandChildField("").parentField(5).childField(2.5).build(); + } +} diff --git a/test/transform/resource/after-ecj/SuperBuilderAbstract.java b/test/transform/resource/after-ecj/SuperBuilderAbstract.java new file mode 100644 index 00000000..2839babd --- /dev/null +++ b/test/transform/resource/after-ecj/SuperBuilderAbstract.java @@ -0,0 +1,102 @@ +public class SuperBuilderAbstract { + public static @lombok.experimental.SuperBuilder class Parent { + public static abstract @java.lang.SuppressWarnings("all") class ParentBuilder> { + private @java.lang.SuppressWarnings("all") int parentField; + 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 parentField(final int parentField) { + this.parentField = parentField; + return self(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (("SuperBuilderAbstract.Parent.ParentBuilder(parentField=" + this.parentField) + ")"); + } + } + private static final @java.lang.SuppressWarnings("all") class ParentBuilderImpl extends ParentBuilder { + private ParentBuilderImpl() { + super(); + } + protected @java.lang.Override @java.lang.SuppressWarnings("all") ParentBuilderImpl self() { + return this; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") Parent build() { + return new Parent(this); + } + } + int parentField; + protected @java.lang.SuppressWarnings("all") Parent(final ParentBuilder b) { + super(); + this.parentField = b.parentField; + } + public static @java.lang.SuppressWarnings("all") ParentBuilder builder() { + return new ParentBuilderImpl(); + } + } + public static abstract @lombok.experimental.SuperBuilder class Child extends Parent { + public static abstract @java.lang.SuppressWarnings("all") class ChildBuilder> extends Parent.ParentBuilder { + private @java.lang.SuppressWarnings("all") double childField; + 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 childField(final double childField) { + this.childField = childField; + return self(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (((("SuperBuilderAbstract.Child.ChildBuilder(super=" + super.toString()) + ", childField=") + this.childField) + ")"); + } + } + double childField; + protected @java.lang.SuppressWarnings("all") Child(final ChildBuilder b) { + super(b); + this.childField = b.childField; + } + } + public static @lombok.experimental.SuperBuilder class GrandChild extends Child { + public static abstract @java.lang.SuppressWarnings("all") class GrandChildBuilder> extends Child.ChildBuilder { + private @java.lang.SuppressWarnings("all") String grandChildField; + public GrandChildBuilder() { + 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 grandChildField(final String grandChildField) { + this.grandChildField = grandChildField; + return self(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (((("SuperBuilderAbstract.GrandChild.GrandChildBuilder(super=" + super.toString()) + ", grandChildField=") + this.grandChildField) + ")"); + } + } + private static final @java.lang.SuppressWarnings("all") class GrandChildBuilderImpl extends GrandChildBuilder { + private GrandChildBuilderImpl() { + super(); + } + protected @java.lang.Override @java.lang.SuppressWarnings("all") GrandChildBuilderImpl self() { + return this; + } + public @java.lang.Override @java.lang.SuppressWarnings("all") GrandChild build() { + return new GrandChild(this); + } + } + String grandChildField; + protected @java.lang.SuppressWarnings("all") GrandChild(final GrandChildBuilder b) { + super(b); + this.grandChildField = b.grandChildField; + } + public static @java.lang.SuppressWarnings("all") GrandChildBuilder builder() { + return new GrandChildBuilderImpl(); + } + } + public SuperBuilderAbstract() { + super(); + } + public static void test() { + GrandChild x = GrandChild.builder().grandChildField("").parentField(5).childField(2.5).build(); + } +} diff --git a/test/transform/resource/before/SuperBuilderAbstract.java b/test/transform/resource/before/SuperBuilderAbstract.java new file mode 100644 index 00000000..23f284e2 --- /dev/null +++ b/test/transform/resource/before/SuperBuilderAbstract.java @@ -0,0 +1,20 @@ +public class SuperBuilderAbstract { + @lombok.experimental.SuperBuilder + public static class Parent { + int parentField; + } + + @lombok.experimental.SuperBuilder + public abstract static class Child extends Parent { + double childField; + } + + @lombok.experimental.SuperBuilder + public static class GrandChild extends Child { + String grandChildField; + } + + public static void test() { + GrandChild x = GrandChild.builder().grandChildField("").parentField(5).childField(2.5).build(); + } +} -- cgit