From 6b0b1a6a7ba73a2c43bb8ab413375505d61aacc6 Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Thu, 29 Mar 2018 03:36:29 +0200 Subject: [builderParentClass] test cases --- .../resource/before/BuilderWithInherit.java | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 test/transform/resource/before/BuilderWithInherit.java (limited to 'test/transform/resource/before') diff --git a/test/transform/resource/before/BuilderWithInherit.java b/test/transform/resource/before/BuilderWithInherit.java new file mode 100644 index 00000000..dcc7b5ad --- /dev/null +++ b/test/transform/resource/before/BuilderWithInherit.java @@ -0,0 +1,20 @@ +import lombok.Builder; +import lombok.Singular; +import java.util.List; + +public class BuilderWithInherit { + @Builder(extensible = true) + public static class Parent { + int field1; + @Singular List items; + } + + @Builder(inherit = true) + public static class Child extends Parent { + double field3; + } + + public static void test() { + Child x = Child.builder().field3(0.0).field1(5).item("").build(); + } +} -- cgit From 3eea3b958946dd813197f00a1292b7a72380878a Mon Sep 17 00:00:00 2001 From: Reinier Zwitserloot Date: Wed, 4 Apr 2018 23:26:01 +0200 Subject: introduction of `@SuperBuilder` and a testcase. --- src/core/lombok/Builder.java | 50 +-------- src/core/lombok/experimental/SuperBuilder.java | 66 ++++++++++++ .../resource/after-delombok/SuperBuilderBasic.java | 112 +++++++++++++++++++++ .../resource/before/BuilderWithInherit.java | 20 ---- .../resource/before/SuperBuilderBasic.java | 20 ++++ 5 files changed, 203 insertions(+), 65 deletions(-) create mode 100644 src/core/lombok/experimental/SuperBuilder.java create mode 100644 test/transform/resource/after-delombok/SuperBuilderBasic.java delete mode 100644 test/transform/resource/before/BuilderWithInherit.java create mode 100644 test/transform/resource/before/SuperBuilderBasic.java (limited to 'test/transform/resource/before') diff --git a/src/core/lombok/Builder.java b/src/core/lombok/Builder.java index 7ae43bfa..d7a2a109 100644 --- a/src/core/lombok/Builder.java +++ b/src/core/lombok/Builder.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2017 The Project Lombok Authors. + * Copyright (C) 2013-2018 The Project Lombok Authors. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -55,8 +55,8 @@ import java.lang.annotation.Target; * *
  * @Builder
- * class Example {
- * 	private int foo;
+ * class Example<T> {
+ * 	private T foo;
  * 	private final String bar;
  * }
  * 
@@ -103,6 +103,8 @@ import java.lang.annotation.Target; * } * } * + * + * @see Singular */ @Target({TYPE, METHOD, CONSTRUCTOR}) @Retention(SOURCE) @@ -131,48 +133,6 @@ public @interface Builder { */ String builderClassName() default ""; - /** - * Should the generated builder extend the parent class's builder? - * - * If {@code true}, the generated builder class will extend the builder of the - * superclass. This means the builder also contains the methods for fields from - * the superclass. - *

- * Note that both this builder and the superclass' builder must be a builder - * for a type (so, not for a static method or a constructor). You must mark - * the parent extendable: {@code @Builder(extensible = true)}. - *

- * This builder will also be {@code extensible = true} if you set {@code inherit = true}. - * - * @see #extensible() - */ - boolean inherit() default false; - - /** - * Should the generated builder be extensible by subclasses? - * - * If {@code true} the generated builder class will be extensible by - * {@code @Builder} classes of this class's subclasses, by marking them - * with {@code @Builder(inherit = true)}. - *

- * The {@code @Builder} extensible system only works for {@code @Builder} - * annotations on types (so, not on a static method or a constructor). - * - * @see #inherit() - */ - boolean extensible() default false; - - /** - * Name of the builder class in the superclass. - * - * Only relevant if {@code inherit = true} - * - * Default: {@code (SuperclassTypeName)Builder}. - * - * @see #inherit() - */ - String superclassBuilderClassName() default ""; - /** * If true, generate an instance method to obtain a builder that is initialized with the values of this instance. * Legal only if {@code @Builder} is used on a constructor, on the type itself, or on a static method that returns diff --git a/src/core/lombok/experimental/SuperBuilder.java b/src/core/lombok/experimental/SuperBuilder.java new file mode 100644 index 00000000..26127a5f --- /dev/null +++ b/src/core/lombok/experimental/SuperBuilder.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2018 The Project Lombok Authors. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.experimental; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.*; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import lombok.Singular; + +/** + * The SuperBuilder annotation creates a so-called 'builder' aspect to the class that is annotated with {@code @SuperBuilder}, but which works well when extending. + * It is similar to {@code @Builder}, except it is only legal on types, is less configurable, but allows you to {@code extends} other builder-able classes. + *

+ * All classes in the hierarchy must be annotated with {@code @SuperBuilder}. + *

+ * Lombok generates 2 inner 'builder' classes, which extend the parent class' builder class (unless your class doesn't have an extends clause). + * Lombok also generates a static method named {@code builder()}, and a protected constructor that takes 1 argument of the builderclass type. + *

+ * The TBuilder class contains 1 method for each parameter of the annotated + * constructor / method (each field, when annotating a class), which returns the builder itself. + * The builder also has a build() method which returns a completed instance of the original type. + *

+ * Complete documentation is found at the project lombok features page for @SuperBuilder. + * + * @see Singular + */ +@Target(TYPE) +@Retention(SOURCE) +public @interface SuperBuilder { + /** @return Name of the method that creates a new builder instance. Default: {@code builder}. */ + String builderMethodName() default "builder"; + + /** @return Name of the method in the builder class that creates an instance of your {@code @Builder}-annotated class. */ + String buildMethodName() default "build"; + + // toBuilder also requires a two-stage system where each class gets its own toBuilder but calls on a second method (and also calls parentclass's method) + // to fill the builder, as this class does not know what fields to pass on to the builder. Let's consider this, but only for milestone 2. + /* + * If true, generate an instance method to obtain a builder that is initialized with the values of this instance. + * + * @return Whether to generate a {@code toBuilder()} method. + */ +// boolean toBuilder() default false; +} diff --git a/test/transform/resource/after-delombok/SuperBuilderBasic.java b/test/transform/resource/after-delombok/SuperBuilderBasic.java new file mode 100644 index 00000000..ffb56e0e --- /dev/null +++ b/test/transform/resource/after-delombok/SuperBuilderBasic.java @@ -0,0 +1,112 @@ +import java.util.List; + +public class SuperBuilderBasic { + public static class Parent { + int field1; + List items; + protected Parent(final ParentBuilder b) { + this.field1 = b.field1; + java.util.List items; + switch (b.items == null ? 0 : b.items.size()) { + case 0: + items = java.util.Collections.emptyList(); + break; + case 1: + items = java.util.Collections.singletonList(b.items.get(0)); + break; + default: + items = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.items)); + } + this.items = items; + } + private static class ParentBuilderImpl extends ParentBuilder { + @Override + public Parent build() { + return new Parent(this); + } + + @Override + public ParentBuilderImpl self() { + return this; + } + } + public abstract static class ParentBuilder> { + @java.lang.SuppressWarnings("all") + private int field1; + @java.lang.SuppressWarnings("all") + private java.util.ArrayList items; + @java.lang.SuppressWarnings("all") + ParentBuilder() { + } + @java.lang.SuppressWarnings("all") + public B field1(final int field1) { + this.field1 = field1; + return self(); + } + @java.lang.SuppressWarnings("all") + public B item(final String item) { + if (this.items == null) this.items = new java.util.ArrayList(); + this.items.add(item); + return self(); + } + @java.lang.SuppressWarnings("all") + public B items(final java.util.Collection items) { + if (this.items == null) this.items = new java.util.ArrayList(); + this.items.addAll(items); + return self(); + } + @java.lang.SuppressWarnings("all") + public B clearItems() { + if (this.items != null) this.items.clear(); + return self(); + } + @java.lang.SuppressWarnings("all") + protected abstract B self(); + @java.lang.SuppressWarnings("all") + public abstract C build(); + } + public static ParentBuilder builder() { + return new ParentBuilderImpl(); + } + } + public static class Child extends Parent { + double field3; + protected Child(ChildBuilder b) { + super(b); + this.field3 = b.field3; + } + private static class ChildBuilderImpl extends ChildBuilder { + @Override + public Child build() { + return new Child(this); + } + + @Override + public ChildBuilderImpl self() { + return this; + } + } + public abstract static class ChildBuilder> extends Parent.ParentBuilder { + @java.lang.SuppressWarnings("all") + private double field3; + @java.lang.SuppressWarnings("all") + ChildBuilder() { + } + @java.lang.SuppressWarnings("all") + public B field3(final double field3) { + this.field3 = field3; + return self(); + } + @java.lang.SuppressWarnings("all") + protected abstract B self(); + @java.lang.SuppressWarnings("all") + public abstract C build(); + } + public static ChildBuilder builder() { + return new ChildBuilderImpl(); + } + } + public static void test() { + Child x = Child.builder().field3(0.0).field1(5).item("").build(); + } +} diff --git a/test/transform/resource/before/BuilderWithInherit.java b/test/transform/resource/before/BuilderWithInherit.java deleted file mode 100644 index dcc7b5ad..00000000 --- a/test/transform/resource/before/BuilderWithInherit.java +++ /dev/null @@ -1,20 +0,0 @@ -import lombok.Builder; -import lombok.Singular; -import java.util.List; - -public class BuilderWithInherit { - @Builder(extensible = true) - public static class Parent { - int field1; - @Singular List items; - } - - @Builder(inherit = true) - public static class Child extends Parent { - double field3; - } - - public static void test() { - Child x = Child.builder().field3(0.0).field1(5).item("").build(); - } -} diff --git a/test/transform/resource/before/SuperBuilderBasic.java b/test/transform/resource/before/SuperBuilderBasic.java new file mode 100644 index 00000000..bf3eea64 --- /dev/null +++ b/test/transform/resource/before/SuperBuilderBasic.java @@ -0,0 +1,20 @@ +import lombok.experimental.SuperBuilder; +import lombok.Singular; +import java.util.List; + +public class SuperBuilderBasic { + @SuperBuilder + public static class Parent { + int field1; + @Singular List items; + } + + @SuperBuilder + public static class Child extends Parent { + double field3; + } + + public static void test() { + Child x = Child.builder().field3(0.0).field1(5).item("").build(); + } +} -- cgit From 9df65559122a572e7ee0ea355f05d2f9a934c7e5 Mon Sep 17 00:00:00 2001 From: Jan Rieke Date: Sun, 15 Apr 2018 23:06:19 +0200 Subject: added SuperBuilder with generics test case --- .../after-delombok/SuperBuilderWithGenerics.java | 166 +++++++++++++++++++++ .../resource/before/SuperBuilderWithGenerics.java | 20 +++ 2 files changed, 186 insertions(+) create mode 100644 test/transform/resource/after-delombok/SuperBuilderWithGenerics.java create mode 100644 test/transform/resource/before/SuperBuilderWithGenerics.java (limited to 'test/transform/resource/before') diff --git a/test/transform/resource/after-delombok/SuperBuilderWithGenerics.java b/test/transform/resource/after-delombok/SuperBuilderWithGenerics.java new file mode 100644 index 00000000..bfd6e4b7 --- /dev/null +++ b/test/transform/resource/after-delombok/SuperBuilderWithGenerics.java @@ -0,0 +1,166 @@ +import java.util.List; + +public class SuperBuilderWithGenerics { + public static class Parent { + A field1; + List items; + + @java.lang.SuppressWarnings("all") + protected Parent(final ParentBuilder b) { + this.field1 = b.field1; + java.util.List items; + switch (b.items == null ? 0 : b.items.size()) { + case 0: + items = java.util.Collections.emptyList(); + break; + + case 1: + items = java.util.Collections.singletonList(b.items.get(0)); + break; + + default: + items = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.items)); + } + this.items = items; + } + + + @java.lang.SuppressWarnings("all") + public static abstract class ParentBuilder, B extends ParentBuilder> { + @java.lang.SuppressWarnings("all") + private A field1; + @java.lang.SuppressWarnings("all") + private java.util.ArrayList items; + + @java.lang.SuppressWarnings("all") + protected abstract B self(); + + @java.lang.SuppressWarnings("all") + public abstract C build(); + + @java.lang.SuppressWarnings("all") + public B field1(final A field1) { + this.field1 = field1; + return self(); + } + + @java.lang.SuppressWarnings("all") + public B item(final String item) { + if (this.items == null) this.items = new java.util.ArrayList(); + this.items.add(item); + return self(); + } + + @java.lang.SuppressWarnings("all") + public B items(final java.util.Collection items) { + if (this.items == null) this.items = new java.util.ArrayList(); + this.items.addAll(items); + return self(); + } + + @java.lang.SuppressWarnings("all") + public B clearItems() { + if (this.items != null) this.items.clear(); + return self(); + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "SuperBuilderWithGenerics.Parent.ParentBuilder(field1=" + this.field1 + ", items=" + this.items + ")"; + } + } + + + @java.lang.SuppressWarnings("all") + private static final class ParentBuilderImpl extends ParentBuilder, ParentBuilderImpl> { + @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") + public static ParentBuilder builder() { + return new ParentBuilderImpl(); + } + } + + + public static class Child extends Parent { + double field3; + + @java.lang.SuppressWarnings("all") + protected Child(final ChildBuilder b) { + super(b); + this.field3 = b.field3; + } + + + @java.lang.SuppressWarnings("all") + public static abstract class ChildBuilder, B extends ChildBuilder> extends Parent.ParentBuilder { + @java.lang.SuppressWarnings("all") + private double field3; + + @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 field3(final double field3) { + this.field3 = field3; + return self(); + } + + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "SuperBuilderWithGenerics.Child.ChildBuilder(field3=" + this.field3 + ")"; + } + } + + + @java.lang.SuppressWarnings("all") + private static final class ChildBuilderImpl extends ChildBuilder, 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") + public static ChildBuilder builder() { + return new ChildBuilderImpl(); + } + } + + public static void test() { + Child x = Child.builder().field3(0.0).field1(5).item("").build(); + } +} diff --git a/test/transform/resource/before/SuperBuilderWithGenerics.java b/test/transform/resource/before/SuperBuilderWithGenerics.java new file mode 100644 index 00000000..7b8d459f --- /dev/null +++ b/test/transform/resource/before/SuperBuilderWithGenerics.java @@ -0,0 +1,20 @@ +import lombok.experimental.SuperBuilder; +import lombok.Singular; +import java.util.List; + +public class SuperBuilderWithGenerics { + @SuperBuilder + public static class Parent { + A field1; + @Singular List items; + } + + @SuperBuilder + public static class Child extends Parent { + double field3; + } + + public static void test() { + Child x = Child.builder().field3(0.0).field1(5).item("").build(); + } +} -- cgit From 4f5d5b108dada037137c209e3b8a3b86af8643ae Mon Sep 17 00:00:00 2001 From: Jan Rieke Date: Fri, 27 Apr 2018 13:36:08 +0200 Subject: fixed javac tests (toString calls super now) --- test/transform/resource/after-delombok/SuperBuilderBasic.java | 5 +++-- .../resource/after-delombok/SuperBuilderWithGenerics.java | 5 +++-- test/transform/resource/before/SuperBuilderBasic.java | 8 +++----- test/transform/resource/before/SuperBuilderWithGenerics.java | 8 +++----- 4 files changed, 12 insertions(+), 14 deletions(-) (limited to 'test/transform/resource/before') diff --git a/test/transform/resource/after-delombok/SuperBuilderBasic.java b/test/transform/resource/after-delombok/SuperBuilderBasic.java index ed1f9bdc..da745b58 100644 --- a/test/transform/resource/after-delombok/SuperBuilderBasic.java +++ b/test/transform/resource/after-delombok/SuperBuilderBasic.java @@ -1,6 +1,7 @@ import java.util.List; public class SuperBuilderBasic { + @lombok.experimental.SuperBuilder public static class Parent { int field1; List items; @@ -97,7 +98,7 @@ public class SuperBuilderBasic { } } - + @lombok.experimental.SuperBuilder public static class Child extends Parent { double field3; @@ -130,7 +131,7 @@ public class SuperBuilderBasic { @java.lang.Override @java.lang.SuppressWarnings("all") public java.lang.String toString() { - return "SuperBuilderBasic.Child.ChildBuilder(field3=" + this.field3 + ")"; + return "SuperBuilderBasic.Child.ChildBuilder(super=" + super.toString() + ", field3=" + this.field3 + ")"; } } diff --git a/test/transform/resource/after-delombok/SuperBuilderWithGenerics.java b/test/transform/resource/after-delombok/SuperBuilderWithGenerics.java index bfd6e4b7..ff080f6c 100644 --- a/test/transform/resource/after-delombok/SuperBuilderWithGenerics.java +++ b/test/transform/resource/after-delombok/SuperBuilderWithGenerics.java @@ -1,6 +1,7 @@ import java.util.List; public class SuperBuilderWithGenerics { + @lombok.experimental.SuperBuilder public static class Parent { A field1; List items; @@ -97,7 +98,7 @@ public class SuperBuilderWithGenerics { } } - + @lombok.experimental.SuperBuilder public static class Child extends Parent { double field3; @@ -130,7 +131,7 @@ public class SuperBuilderWithGenerics { @java.lang.Override @java.lang.SuppressWarnings("all") public java.lang.String toString() { - return "SuperBuilderWithGenerics.Child.ChildBuilder(field3=" + this.field3 + ")"; + return "SuperBuilderWithGenerics.Child.ChildBuilder(super=" + super.toString() + ", field3=" + this.field3 + ")"; } } diff --git a/test/transform/resource/before/SuperBuilderBasic.java b/test/transform/resource/before/SuperBuilderBasic.java index bf3eea64..f4e8c670 100644 --- a/test/transform/resource/before/SuperBuilderBasic.java +++ b/test/transform/resource/before/SuperBuilderBasic.java @@ -1,15 +1,13 @@ -import lombok.experimental.SuperBuilder; -import lombok.Singular; import java.util.List; public class SuperBuilderBasic { - @SuperBuilder + @lombok.experimental.SuperBuilder public static class Parent { int field1; - @Singular List items; + @lombok.Singular List items; } - @SuperBuilder + @lombok.experimental.SuperBuilder public static class Child extends Parent { double field3; } diff --git a/test/transform/resource/before/SuperBuilderWithGenerics.java b/test/transform/resource/before/SuperBuilderWithGenerics.java index 7b8d459f..c3cd4277 100644 --- a/test/transform/resource/before/SuperBuilderWithGenerics.java +++ b/test/transform/resource/before/SuperBuilderWithGenerics.java @@ -1,15 +1,13 @@ -import lombok.experimental.SuperBuilder; -import lombok.Singular; import java.util.List; public class SuperBuilderWithGenerics { - @SuperBuilder + @lombok.experimental.SuperBuilder public static class Parent { A field1; - @Singular List items; + @lombok.Singular List items; } - @SuperBuilder + @lombok.experimental.SuperBuilder public static class Child extends Parent { double field3; } -- cgit From 1e87330f1825f1072fd2ce7eba15fb10e9e080e7 Mon Sep 17 00:00:00 2001 From: Jan Rieke Date: Wed, 30 May 2018 22:50:09 +0200 Subject: test case for custom builder method --- .../SuperBuilderWithCustomBuilderMethod.java | 134 +++++++++++++++++++++ .../SuperBuilderWithCustomBuilderMethod.java | 103 ++++++++++++++++ .../SuperBuilderWithCustomBuilderMethod.java | 21 ++++ 3 files changed, 258 insertions(+) create mode 100644 test/transform/resource/after-delombok/SuperBuilderWithCustomBuilderMethod.java create mode 100644 test/transform/resource/after-ecj/SuperBuilderWithCustomBuilderMethod.java create mode 100644 test/transform/resource/before/SuperBuilderWithCustomBuilderMethod.java (limited to 'test/transform/resource/before') diff --git a/test/transform/resource/after-delombok/SuperBuilderWithCustomBuilderMethod.java b/test/transform/resource/after-delombok/SuperBuilderWithCustomBuilderMethod.java new file mode 100644 index 00000000..19e7a2b3 --- /dev/null +++ b/test/transform/resource/after-delombok/SuperBuilderWithCustomBuilderMethod.java @@ -0,0 +1,134 @@ +import java.util.List; +public class SuperBuilderWithCustomBuilderMethod { + @lombok.experimental.SuperBuilder + public static class Parent { + A field1; + List items; + @java.lang.SuppressWarnings("all") + public static abstract class ParentBuilder, B extends ParentBuilder> { + @java.lang.SuppressWarnings("all") + private A field1; + @java.lang.SuppressWarnings("all") + private java.util.ArrayList items; + @java.lang.SuppressWarnings("all") + protected abstract B self(); + @java.lang.SuppressWarnings("all") + public abstract C build(); + @java.lang.SuppressWarnings("all") + public B field1(final A field1) { + this.field1 = field1; + return self(); + } + @java.lang.SuppressWarnings("all") + public B item(final String item) { + if (this.items == null) this.items = new java.util.ArrayList(); + this.items.add(item); + return self(); + } + @java.lang.SuppressWarnings("all") + public B items(final java.util.Collection items) { + if (this.items == null) this.items = new java.util.ArrayList(); + this.items.addAll(items); + return self(); + } + @java.lang.SuppressWarnings("all") + public B clearItems() { + if (this.items != null) this.items.clear(); + return self(); + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "SuperBuilderWithGenerics.Parent.ParentBuilder(field1=" + this.field1 + ", items=" + this.items + ")"; + } + } + @java.lang.SuppressWarnings("all") + private static final class ParentBuilderImpl extends ParentBuilder, ParentBuilderImpl> { + @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.field1 = b.field1; + java.util.List items; + switch (b.items == null ? 0 : b.items.size()) { + case 0: + items = java.util.Collections.emptyList(); + break; + case 1: + items = java.util.Collections.singletonList(b.items.get(0)); + break; + default: + items = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.items)); + } + this.items = items; + } + @java.lang.SuppressWarnings("all") + public static ParentBuilder builder() { + return new ParentBuilderImpl(); + } + } + @lombok.experimental.SuperBuilder + public static class Child extends Parent { + double field3; + @java.lang.SuppressWarnings("all") + public static abstract class ChildBuilder, B extends ChildBuilder> extends Parent.ParentBuilder { + @java.lang.SuppressWarnings("all") + private double field3; + @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 field3(final double field3) { + this.field3 = field3; + return self(); + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "SuperBuilderWithGenerics.Child.ChildBuilder(super=" + super.toString() + ", field3=" + this.field3 + ")"; + } + } + @java.lang.SuppressWarnings("all") + private static final class ChildBuilderImpl extends ChildBuilder, 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); + this.field3 = b.field3; + } + public static ChildBuilder builder() { + return new ChildBuilderImpl().item("default item"); + } + } + public static void test() { + Child x = Child.builder().field3(0.0).field1(5).item("").build(); + } +} diff --git a/test/transform/resource/after-ecj/SuperBuilderWithCustomBuilderMethod.java b/test/transform/resource/after-ecj/SuperBuilderWithCustomBuilderMethod.java new file mode 100644 index 00000000..2f4048d6 --- /dev/null +++ b/test/transform/resource/after-ecj/SuperBuilderWithCustomBuilderMethod.java @@ -0,0 +1,103 @@ +import java.util.List; +public class SuperBuilderWithCustomBuilderMethod { + public static @lombok.experimental.SuperBuilder class Parent { + public static abstract @java.lang.SuppressWarnings("all") class ParentBuilder, B extends ParentBuilder> { + private @java.lang.SuppressWarnings("all") A field1; + private @java.lang.SuppressWarnings("all") java.util.ArrayList items; + protected abstract @java.lang.SuppressWarnings("all") B self(); + public abstract @java.lang.SuppressWarnings("all") C build(); + public @java.lang.SuppressWarnings("all") B field1(final A field1) { + this.field1 = field1; + return self(); + } + public @java.lang.SuppressWarnings("all") B item(String item) { + if ((this.items == null)) + this.items = new java.util.ArrayList(); + this.items.add(item); + return self(); + } + public @java.lang.SuppressWarnings("all") B items(java.util.Collection items) { + if ((this.items == null)) + this.items = new java.util.ArrayList(); + this.items.addAll(items); + return self(); + } + public @java.lang.SuppressWarnings("all") B clearItems() { + if ((this.items != null)) + this.items.clear(); + return self(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (((("SuperBuilderWithGenerics.Parent.ParentBuilder(field1=" + this.field1) + ", items=") + this.items) + ")"); + } + } + private static final @java.lang.SuppressWarnings("all") class ParentBuilderImpl extends ParentBuilder, ParentBuilderImpl> { + private @java.lang.SuppressWarnings("all") ParentBuilderImpl() { + } + 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); + } + } + A field1; + @lombok.Singular List items; + protected @java.lang.SuppressWarnings("all") Parent(final ParentBuilder b) { + this.field1 = b.field1; + java.util.List items; + switch (((b.items == null) ? 0 : b.items.size())) { + case 0 : + items = java.util.Collections.emptyList(); + break; + case 1 : + items = java.util.Collections.singletonList(b.items.get(0)); + break; + default : + items = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.items)); + } + this.items = items; + } + public static @java.lang.SuppressWarnings("all") ParentBuilder builder() { + return new ParentBuilderImpl(); + } + } + public static @lombok.experimental.SuperBuilder class Child extends Parent { + public static abstract @java.lang.SuppressWarnings("all") class ChildBuilder, B extends ChildBuilder> extends Parent.ParentBuilder { + private @java.lang.SuppressWarnings("all") double field3; + 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 field3(final double field3) { + this.field3 = field3; + return self(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (((("SuperBuilderWithGenerics.Child.ChildBuilder(super=" + super.toString()) + ", field3=") + this.field3) + ")"); + } + } + private static final @java.lang.SuppressWarnings("all") class ChildBuilderImpl extends ChildBuilder, ChildBuilderImpl> { + private @java.lang.SuppressWarnings("all") ChildBuilderImpl() { + } + 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); + } + } + double field3; + protected @java.lang.SuppressWarnings("all") Child(final ChildBuilder b) { + super(b); + this.field3 = b.field3; + } + public static @java.lang.SuppressWarnings("all") ChildBuilder builder() { + return new ChildBuilderImpl().item("default item"); + } + } + public SuperBuilderWithGenerics() { + super(); + } + public static void test() { + Child x = Child.builder().field3(0.0).field1(5).item("").build(); + } +} diff --git a/test/transform/resource/before/SuperBuilderWithCustomBuilderMethod.java b/test/transform/resource/before/SuperBuilderWithCustomBuilderMethod.java new file mode 100644 index 00000000..d52cbded --- /dev/null +++ b/test/transform/resource/before/SuperBuilderWithCustomBuilderMethod.java @@ -0,0 +1,21 @@ +import java.util.List; + +public class SuperBuilderWithCustomBuilderMethod { + @lombok.experimental.SuperBuilder + public static class Parent { + A field1; + @lombok.Singular List items; + } + + @lombok.experimental.SuperBuilder + public static class Child extends Parent { + double field3; + public static ChildBuilder builder() { + return new ChildBuilderImpl().item("default item"); + } + } + + public static void test() { + Child x = Child.builder().field3(0.0).field1(5).item("").build(); + } +} -- cgit From 7bd60ea6e68699b9b75f6fb4ce8c68abfa69f5de Mon Sep 17 00:00:00 2001 From: Jan Rieke Date: Thu, 31 May 2018 16:32:14 +0200 Subject: second generics test case --- .../eclipse/handlers/HandleSuperBuilder.java | 5 +- .../after-delombok/SuperBuilderWithGenerics2.java | 133 +++++++++++++++++++++ .../after-ecj/SuperBuilderWithGenerics2.java | 103 ++++++++++++++++ .../resource/before/SuperBuilderWithGenerics2.java | 18 +++ 4 files changed, 256 insertions(+), 3 deletions(-) create mode 100644 test/transform/resource/after-delombok/SuperBuilderWithGenerics2.java create mode 100644 test/transform/resource/after-ecj/SuperBuilderWithGenerics2.java create mode 100644 test/transform/resource/before/SuperBuilderWithGenerics2.java (limited to 'test/transform/resource/before') diff --git a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java index d452261a..d4441831 100644 --- a/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java +++ b/src/core/lombok/eclipse/handlers/HandleSuperBuilder.java @@ -141,7 +141,6 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { java.util.List builderFields = new ArrayList(); TypeReference returnType; TypeParameter[] typeParams; - TypeParameter[] superclassTypeParams = new TypeParameter[] {}; //TODO boolean addCleaning = false; @@ -267,7 +266,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { EclipseNode builderType = findInnerClass(tdParent, builderClassName); if (builderType == null) { builderType = generateBuilderAbstractClass(tdParent, builderClassName, superclassBuilderClass, - typeParams, superclassTypeParams, ast, classGenericName, builderGenericName); + typeParams, ast, classGenericName, builderGenericName); } else { annotationNode.addError("@SuperBuilder does not support customized builders. Use @Builder instead."); @@ -360,7 +359,7 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { private EclipseNode generateBuilderAbstractClass(EclipseNode tdParent, String builderClass, TypeReference superclassBuilderClass, TypeParameter[] typeParams, - TypeParameter[] superclassTypeParams, ASTNode source, String classGenericName, String builderGenericName) { + ASTNode source, String classGenericName, String builderGenericName) { TypeDeclaration parent = (TypeDeclaration) tdParent.get(); TypeDeclaration builder = new TypeDeclaration(parent.compilationResult); diff --git a/test/transform/resource/after-delombok/SuperBuilderWithGenerics2.java b/test/transform/resource/after-delombok/SuperBuilderWithGenerics2.java new file mode 100644 index 00000000..811fd7e8 --- /dev/null +++ b/test/transform/resource/after-delombok/SuperBuilderWithGenerics2.java @@ -0,0 +1,133 @@ +import java.util.List; +public class SuperBuilderWithGenerics2 { + public static class Parent { + A field1; + List items; + @java.lang.SuppressWarnings("all") + public static abstract class ParentBuilder, B extends ParentBuilder> { + @java.lang.SuppressWarnings("all") + private A field1; + @java.lang.SuppressWarnings("all") + private java.util.ArrayList items; + @java.lang.SuppressWarnings("all") + protected abstract B self(); + @java.lang.SuppressWarnings("all") + public abstract C build(); + @java.lang.SuppressWarnings("all") + public B field1(final A field1) { + this.field1 = field1; + return self(); + } + @java.lang.SuppressWarnings("all") + public B item(final String item) { + if (this.items == null) this.items = new java.util.ArrayList(); + this.items.add(item); + return self(); + } + @java.lang.SuppressWarnings("all") + public B items(final java.util.Collection items) { + if (this.items == null) this.items = new java.util.ArrayList(); + this.items.addAll(items); + return self(); + } + @java.lang.SuppressWarnings("all") + public B clearItems() { + if (this.items != null) this.items.clear(); + return self(); + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "SuperBuilderWithGenerics2.Parent.ParentBuilder(field1=" + this.field1 + ", items=" + this.items + ")"; + } + } + @java.lang.SuppressWarnings("all") + private static final class ParentBuilderImpl extends ParentBuilder, ParentBuilderImpl> { + @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.field1 = b.field1; + java.util.List items; + switch (b.items == null ? 0 : b.items.size()) { + case 0: + items = java.util.Collections.emptyList(); + break; + case 1: + items = java.util.Collections.singletonList(b.items.get(0)); + break; + default: + items = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.items)); + } + this.items = items; + } + @java.lang.SuppressWarnings("all") + public static ParentBuilder builder() { + return new ParentBuilderImpl(); + } + } + public static class Child extends Parent { + A field3; + @java.lang.SuppressWarnings("all") + public static abstract class ChildBuilder, B extends ChildBuilder> extends Parent.ParentBuilder { + @java.lang.SuppressWarnings("all") + private A field3; + @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 field3(final A field3) { + this.field3 = field3; + return self(); + } + @java.lang.Override + @java.lang.SuppressWarnings("all") + public java.lang.String toString() { + return "SuperBuilderWithGenerics2.Child.ChildBuilder(super=" + super.toString() + ", field3=" + this.field3 + ")"; + } + } + @java.lang.SuppressWarnings("all") + private static final class ChildBuilderImpl extends ChildBuilder, 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); + this.field3 = b.field3; + } + @java.lang.SuppressWarnings("all") + public static ChildBuilder builder2() { + return new ChildBuilderImpl(); + } + } + public static void test() { + Child x = Child.builder2().field3(1).field1("value").item("").build(); + } +} diff --git a/test/transform/resource/after-ecj/SuperBuilderWithGenerics2.java b/test/transform/resource/after-ecj/SuperBuilderWithGenerics2.java new file mode 100644 index 00000000..74cf376e --- /dev/null +++ b/test/transform/resource/after-ecj/SuperBuilderWithGenerics2.java @@ -0,0 +1,103 @@ +import java.util.List; +public class SuperBuilderWithGenerics2 { + public static @lombok.experimental.SuperBuilder class Parent { + public static abstract @java.lang.SuppressWarnings("all") class ParentBuilder, B extends ParentBuilder> { + private @java.lang.SuppressWarnings("all") A field1; + private @java.lang.SuppressWarnings("all") java.util.ArrayList items; + protected abstract @java.lang.SuppressWarnings("all") B self(); + public abstract @java.lang.SuppressWarnings("all") C build(); + public @java.lang.SuppressWarnings("all") B field1(final A field1) { + this.field1 = field1; + return self(); + } + public @java.lang.SuppressWarnings("all") B item(String item) { + if ((this.items == null)) + this.items = new java.util.ArrayList(); + this.items.add(item); + return self(); + } + public @java.lang.SuppressWarnings("all") B items(java.util.Collection items) { + if ((this.items == null)) + this.items = new java.util.ArrayList(); + this.items.addAll(items); + return self(); + } + public @java.lang.SuppressWarnings("all") B clearItems() { + if ((this.items != null)) + this.items.clear(); + return self(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (((("SuperBuilderWithGenerics2.Parent.ParentBuilder(field1=" + this.field1) + ", items=") + this.items) + ")"); + } + } + private static final @java.lang.SuppressWarnings("all") class ParentBuilderImpl extends ParentBuilder, ParentBuilderImpl> { + private @java.lang.SuppressWarnings("all") ParentBuilderImpl() { + } + 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); + } + } + A field1; + @lombok.Singular List items; + protected @java.lang.SuppressWarnings("all") Parent(final ParentBuilder b) { + this.field1 = b.field1; + java.util.List items; + switch (((b.items == null) ? 0 : b.items.size())) { + case 0 : + items = java.util.Collections.emptyList(); + break; + case 1 : + items = java.util.Collections.singletonList(b.items.get(0)); + break; + default : + items = java.util.Collections.unmodifiableList(new java.util.ArrayList(b.items)); + } + this.items = items; + } + public static @java.lang.SuppressWarnings("all") ParentBuilder builder() { + return new ParentBuilderImpl(); + } + } + public static @lombok.experimental.SuperBuilder(builderMethodName = "builder2") class Child extends Parent { + public static abstract @java.lang.SuppressWarnings("all") class ChildBuilder, B extends ChildBuilder> extends Parent.ParentBuilder { + private @java.lang.SuppressWarnings("all") A field3; + 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 field3(final A field3) { + this.field3 = field3; + return self(); + } + public @java.lang.Override @java.lang.SuppressWarnings("all") java.lang.String toString() { + return (((("SuperBuilderWithGenerics2.Child.ChildBuilder(super=" + super.toString()) + ", field3=") + this.field3) + ")"); + } + } + private static final @java.lang.SuppressWarnings("all") class ChildBuilderImpl extends ChildBuilder, ChildBuilderImpl> { + private @java.lang.SuppressWarnings("all") ChildBuilderImpl() { + } + 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); + } + } + A field3; + protected @java.lang.SuppressWarnings("all") Child(final ChildBuilder b) { + super(b); + this.field3 = b.field3; + } + public static @java.lang.SuppressWarnings("all") ChildBuilder builder2() { + return new ChildBuilderImpl(); + } + } + public SuperBuilderWithGenerics2() { + super(); + } + public static void test() { + Child x = Child.builder2().field3(1).field1("value").item("").build(); + } +} diff --git a/test/transform/resource/before/SuperBuilderWithGenerics2.java b/test/transform/resource/before/SuperBuilderWithGenerics2.java new file mode 100644 index 00000000..f84ff1f5 --- /dev/null +++ b/test/transform/resource/before/SuperBuilderWithGenerics2.java @@ -0,0 +1,18 @@ +import java.util.List; + +public class SuperBuilderWithGenerics2 { + @lombok.experimental.SuperBuilder + public static class Parent { + A field1; + @lombok.Singular List items; + } + + @lombok.experimental.SuperBuilder(builderMethodName="builder2") + public static class Child extends Parent { + A field3; + } + + public static void test() { + Child x = Child.builder2().field3(1).field1("value").item("").build(); + } +} -- cgit From d11263a6c60008894213a1b465f2b16be3a03468 Mon Sep 17 00:00:00 2001 From: Jan Rieke Date: Fri, 1 Jun 2018 13:48:38 +0200 Subject: support @Builder.Default --- .../eclipse/handlers/HandleBuilderDefault.java | 6 +- .../eclipse/handlers/HandleSuperBuilder.java | 40 ++++--- .../javac/handlers/HandleBuilderDefault.java | 6 +- .../lombok/javac/handlers/HandleSuperBuilder.java | 42 ++++---- .../after-delombok/SuperBuilderWithDefaults.java | 119 +++++++++++++++++++++ .../after-ecj/SuperBuilderWithDefaults.java | 97 +++++++++++++++++ .../resource/before/SuperBuilderWithDefaults.java | 18 ++++ .../features/experimental/SuperBuilder.html | 4 +- 8 files changed, 290 insertions(+), 42 deletions(-) create mode 100644 test/transform/resource/after-delombok/SuperBuilderWithDefaults.java create mode 100644 test/transform/resource/after-ecj/SuperBuilderWithDefaults.java create mode 100644 test/transform/resource/before/SuperBuilderWithDefaults.java (limited to 'test/transform/resource/before') diff --git a/src/core/lombok/eclipse/handlers/HandleBuilderDefault.java b/src/core/lombok/eclipse/handlers/HandleBuilderDefault.java index be2b986d..d0c597fd 100644 --- a/src/core/lombok/eclipse/handlers/HandleBuilderDefault.java +++ b/src/core/lombok/eclipse/handlers/HandleBuilderDefault.java @@ -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 { 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 { TypeReference type; char[] rawName; char[] name; - char[] nameOfDefaultProvider; char[] nameOfSetFlag; SingularData singularData; ObtainVia obtainVia; @@ -185,13 +184,16 @@ public class HandleSuperBuilder extends EclipseAnnotationHandler { } 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 { 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 { 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 { 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 { @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); } }; diff --git a/src/core/lombok/javac/handlers/HandleBuilderDefault.java b/src/core/lombok/javac/handlers/HandleBuilderDefault.java index 4c4ba0e8..af45a620 100644 --- a/src/core/lombok/javac/handlers/HandleBuilderDefault.java +++ b/src/core/lombok/javac/handlers/HandleBuilderDefault.java @@ -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 { JCExpression type; Name rawName; Name name; - Name nameOfDefaultProvider; Name nameOfSetFlag; SingularData singularData; ObtainVia obtainVia; @@ -164,13 +164,16 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { } 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 { } 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.nil()); @@ -575,18 +585,6 @@ public class HandleSuperBuilder extends JavacAnnotationHandler { return maker.MethodDef(maker.Modifiers(Flags.PUBLIC), type.toName("$lombokClean"), maker.Type(Javac.createVoidType(type.getSymbolTable(), CTC_VOID)), List.nil(), List.nil(), List.nil(), body, null); } - private JCMethodDecl generateDefaultProvider(Name methodName, JavacNode fieldNode, List 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.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.nil(), List.nil(), body, null); - } - private void generateBuilderFields(JavacNode builderType, java.util.List builderFields, JCTree source) { int len = builderFields.size(); java.util.List existing = new ArrayList(); diff --git a/test/transform/resource/after-delombok/SuperBuilderWithDefaults.java b/test/transform/resource/after-delombok/SuperBuilderWithDefaults.java new file mode 100644 index 00000000..7b6b4578 --- /dev/null +++ b/test/transform/resource/after-delombok/SuperBuilderWithDefaults.java @@ -0,0 +1,119 @@ +import java.util.List; +public class SuperBuilderWithDefaults { + public static class Parent { + private long millis = System.currentTimeMillis(); + private N numberField = null; + @java.lang.SuppressWarnings("all") + public static abstract class ParentBuilder, B extends ParentBuilder> { + @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 extends ParentBuilder, ParentBuilderImpl> { + @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) { + if (b.millis$set) this.millis = b.millis; + if (b.numberField$set) this.numberField = b.numberField; + } + @java.lang.SuppressWarnings("all") + public static ParentBuilder builder() { + return new ParentBuilderImpl(); + } + } + public static class Child extends Parent { + private double doubleField = Math.PI; + @java.lang.SuppressWarnings("all") + public static abstract class ChildBuilder> extends Parent.ParentBuilder { + @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 { + @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(); + } +} diff --git a/test/transform/resource/after-ecj/SuperBuilderWithDefaults.java b/test/transform/resource/after-ecj/SuperBuilderWithDefaults.java new file mode 100644 index 00000000..f0e3d8be --- /dev/null +++ b/test/transform/resource/after-ecj/SuperBuilderWithDefaults.java @@ -0,0 +1,97 @@ +import java.util.List; +public class SuperBuilderWithDefaults { + public static @lombok.experimental.SuperBuilder class Parent { + public static abstract @java.lang.SuppressWarnings("all") class ParentBuilder, B extends ParentBuilder> { + 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 extends ParentBuilder, ParentBuilderImpl> { + 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); + } + } + private @lombok.Builder.Default long millis = System.currentTimeMillis(); + private @lombok.Builder.Default N numberField = null; + protected @java.lang.SuppressWarnings("all") Parent(final ParentBuilder b) { + super(); + if (b.millis$set) + this.millis = b.millis; + if (b.numberField$set) + this.numberField = b.numberField; + } + public static @java.lang.SuppressWarnings("all") ParentBuilder builder() { + return new ParentBuilderImpl(); + } + } + public static @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 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 { + 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(); + } +} diff --git a/test/transform/resource/before/SuperBuilderWithDefaults.java b/test/transform/resource/before/SuperBuilderWithDefaults.java new file mode 100644 index 00000000..d6859a78 --- /dev/null +++ b/test/transform/resource/before/SuperBuilderWithDefaults.java @@ -0,0 +1,18 @@ +import java.util.List; + +public class SuperBuilderWithDefaults { + @lombok.experimental.SuperBuilder + public static class Parent { + @lombok.Builder.Default private long millis = System.currentTimeMillis(); + @lombok.Builder.Default private N numberField = null; + } + + @lombok.experimental.SuperBuilder + public static class Child extends Parent { + @lombok.Builder.Default private double doubleField = Math.PI; + } + + public static void test() { + Child x = Child.builder().doubleField(0.1).numberField(5).millis(1234567890L).build(); + } +} diff --git a/website/templates/features/experimental/SuperBuilder.html b/website/templates/features/experimental/SuperBuilder.html index a1e8cb4d..a36ae499 100644 --- a/website/templates/features/experimental/SuperBuilder.html +++ b/website/templates/features/experimental/SuperBuilder.html @@ -23,6 +23,8 @@ Therefore, a @SuperBuilder must extend the @SuperBuilder 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. @SuperBuilder 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. +

+ @SuperBuilder is not compatible with @Builder.

To ensure type-safety, @SuperBuilder generates two inner builder classes for each annotated class, one abstract and one concrete class named FoobarBuilder and FoobarBuilderImpl (where Foobar is the name of the annotated class).

@@ -43,7 +45,7 @@ <@f.confKeys>

- lombok.builder.flagUsage = [warning | error] (default: not set) + lombok.superBuilder.flagUsage = [warning | error] (default: not set)
Lombok will flag any usage of @SuperBuilder as a warning or error if configured.
-- cgit 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 (limited to 'test/transform/resource/before') 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