0

I'm using Lombok's @Builder annotation and need to add a custom setter method, as well as enhancing the build() method.

However, I'm stuck with two solutions where none covers both requirements at once and one contradicts the other.

They vary between the direct Builder override and an inherited Builder.

The code contains those two variants and describes what is and what isn't working.

public class LombokCustomBuilderWithCustomSetterAndBuildMethodExamples {


    /**
     * Without builder inheritance
     */
    @Builder
    public static class ExampleA {

        private String someField;

        /**
         * Directly overwrites the Lombok builder
         */
        private static class ExampleABuilder {

            /**
             * this works
             */
            public ExampleABuilder someCustomSetter(String someValue) {
                this.someField = someValue.toUpperCase();
                return this;
            }

            /**
             * super.builder() not available, as we have overwritten the Lombok's build() method entirely.
             * We would need to re-implement the functionality by ourselves
             */
            public ExampleA build() {
                ExampleA myCreatedObject = super.build();

                if (myCreatedObject.someField == null) throw new RuntimeException("Some validation failed");

                return myCreatedObject;
            }

        }
    }


    /**
     * With child and parent builder inheritance
     */
    @Builder
    public static class ExampleB {

        private String someField;

        private static class CustomExampleBBuilder extends ExampleBBuilder {

            /**
             * this does not work, as this.someField now has private access
             */
            public CustomExampleBBuilder someCustomSetter(String someValue) {
                this.someField = someValue.toUpperCase();
                return this;
            }

            /**
             * This works, super.build() is available, we are using the Lombok's build() result
             * and won't have to rewrite it
             */
            @Override
            public ExampleB build() {
                ExampleB myCreatedObject = super.build();

                if (myCreatedObject.someField == null) throw new RuntimeException("Some validation failed");

                return myCreatedObject;
            }

        }
    }
}

On one hand, I'd need the inheritance so the build() method does not need to be reimplemented, on the other hand I cannot access the field of the class I need to set with the custom setter method.

How can I reuse the existing build() method's result after the object has been built and at the same time have my custom setter method?

talex
  • 17,973
  • 3
  • 29
  • 66
Marian Klühspies
  • 15,824
  • 16
  • 93
  • 136
  • Not sure about the requirements - seeing you found a solution by yourself. Just out of curiosity - is "someField" an additional field (not part of the original object) ? – swinkler Oct 14 '22 at 11:43
  • @swinkler no its not additional. In the real code there are some object modifications within the setter and the given list is transformed and added to multiple fields at once. – Marian Klühspies Oct 14 '22 at 11:44

1 Answers1

0

I solved it by combining both approaches.

  1. The default builder override to add the custom setter
  2. The inherited CustomBuilder to reuse the build() method

The only thing that was required to be done in addition was to also override the builder() method, so the CustomBuilder will be used instead of the default Builder


import lombok.Builder;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class LombokCustomBuilderWithCustomSetterAndBuildMethodExamplesTest {

    public static final String APPENDIX = " - modified by custom build()";

    @Test
    void test() {
        assertEquals("TEST" + APPENDIX, ExampleC.builder().someCustomSetter("test").build().someField);
    }

    /**
     * Combination of both
     */
    @Builder
    public static class ExampleC {

        private String someField;

        /**
         * So the CustomExampleCBuilder will be provided instead
         * of the ExampleCBuilder 
         */
        public static CustomExampleCBuilder builder() {
            return new CustomExampleCBuilder();
        }

        /**
         * Create a base builder override to only add "someCustomeSetter" and keep
         * the rest of Lombok's methods by not overriding them
         */
        private static class ExampleCBuilder {

            public ExampleCBuilder someCustomSetter(String someValue) {
                this.someField = someValue.toUpperCase();
                return this;
            }

        }

        /**
         * Create a child to use the Lombok .build() and enhance it
         */
        private static class CustomExampleCBuilder extends ExampleCBuilder {
            @Override
            public ExampleC build() {
                ExampleC myCreatedObject = super.build();

                if (myCreatedObject.someField == null) throw new RuntimeException("Some validation failed");

                myCreatedObject.someField += APPENDIX;

                return myCreatedObject;
            }
        }
    }

}
Marian Klühspies
  • 15,824
  • 16
  • 93
  • 136