anaptecs / jeaf-generator

JEAF Generator uses UML models to generate code for Spring, REST, OpenAPI, Java and others. Boost your software development efficiency and time-to-market. Bye bye handwritten boiler blade code.
https://www.jeaf-generator.io
Apache License 2.0
2 stars 1 forks source link

Generic Builders #223

Open robinste opened 1 week ago

robinste commented 1 week ago

Feature Description

The current approach with "extendable" Builders does not scale well. Every sub-Builder must override all methods from the parent to narrow the return type.

This particularly annoying when adding a custom "setter" to the Builder of an abstract POJO (using custom implementation). Here each sub-type also must use a custom implementation just to override the Builder return types.


Describe the solution you'd like

Add a generator option to use generic Builders.


@SuperBuilder in Lombok

As an inspiration, you can look at @SuperBuilder from Lombok.

Code before

    @SuperBuilder
    static class X {
        String x;
    }

    @SuperBuilder
    static class Y extends X {
        int y;
    }

Code after

Generated using "Delombok"

    class X {
        String x;

        protected X(XBuilder<?, ?> b) {
            this.x = b.x;
        }

        public static XBuilder<?, ?> builder() {
            return new XBuilderImpl();
        }

        public static abstract class XBuilder<C extends X, B extends XBuilder<C, B>> {

            private String x;

            public B x(String x) {
                this.x = x;
                return self();
            }

            protected abstract B self();

            public abstract C build();

            public String toString() {
                return "X.XBuilder(x=" + this.x + ")";
            }
        }

        private static final class XBuilderImpl extends XBuilder<X, XBuilderImpl> {

            private XBuilderImpl() {
            }

            protected XBuilderImpl self() {
                return this;
            }

            public X build() {
                return new X(this);
            }
        }
    }

    class Y extends X {
        int y;

        protected Y(YBuilder<?, ?> b) {
            super(b);
            this.y = b.y;
        }

        public static YBuilder<?, ?> builder() {
            return new YBuilderImpl();
        }

        public static abstract class YBuilder<C extends Y, B extends YBuilder<C, B>> extends XBuilder<C, B> {

            private int y;

            public B y(int y) {
                this.y = y;
                return self();
            }

            protected abstract B self();

            public abstract C build();

            public String toString() {
                return "Y.YBuilder(super=" + super.toString() + ", y=" + this.y + ")";
            }
        }

        private static final class YBuilderImpl extends YBuilder<Y, YBuilderImpl> {

            private YBuilderImpl() {
            }

            protected YBuilderImpl self() {
                return this;
            }

            public Y build() {
                return new Y(this);
            }
        }
    }