Lombok @Builder and JPA Default constructor

前端 未结 8 1859
遇见更好的自我
遇见更好的自我 2020-12-04 11:03

I\'m using project Lombok together with Spring Data JPA. Is there any way to connect Lombok @Builder with JPA default constructor?

Code:



        
相关标签:
8条回答
  • 2020-12-04 11:25

    Jeff's answer works fine however, @Builder does not support self-reference relationships yet.

    Check this question for more details:

    JPA @OnetoOne self reference relationship with both columns non null

    0 讨论(0)
  • 2020-12-04 11:27

    Updated

    Based on the feedback and John's answer I have updated the answer to no longer use @Tolerate or @Data and instead we create accessors and mutators via @Getter and @Setter, create the default constructor via @NoArgsConstructor, and finally we create the all args constructor that the builder requires via @AllArgsConstructor.

    Since you want to use the builder pattern I imagine you want to restrict visibility of the constructor and mutators methods. To achieve this we set the visibility to package private via the access attribute on the @NoArgsConstructor and @AllArgsConstructor annotations and the value attribute on the @Setterannotation.

    Important

    Remember to properly override toString, equals, and hashCode. See the following posts by Vlad Mihalcea for details:

    • the-best-way-to-implement-equals-hashcode-and-tostring-with-jpa-and-hibernate
    • how-to-implement-equals-and-hashcode-using-the-jpa-entity-identifier
    • hibernate-facts-equals-and-hashcode
    package com.stackoverflow.SO34299054;
    
    import static org.junit.Assert.*;
    
    import java.util.Random;
    
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    
    import org.junit.Test;
    
    import lombok.AccessLevel;
    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Getter;
    import lombok.NoArgsConstructor;
    import lombok.Setter;
    
    @SuppressWarnings("javadoc")
    public class Answer {
    
        @Entity
        @Builder(toBuilder = true)
        @AllArgsConstructor(access = AccessLevel.PACKAGE)
        @NoArgsConstructor(access = AccessLevel.PACKAGE)
        @Setter(value = AccessLevel.PACKAGE)
        @Getter
        public static class Person {
    
            @Id
            @GeneratedValue(strategy = GenerationType.AUTO)
            private Long id;
    
            /*
             * IMPORTANT:
             * Set toString, equals, and hashCode as described in these
             * documents:
             * - https://vladmihalcea.com/the-best-way-to-implement-equals-hashcode-and-tostring-with-jpa-and-hibernate/
             * - https://vladmihalcea.com/how-to-implement-equals-and-hashcode-using-the-jpa-entity-identifier/
             * - https://vladmihalcea.com/hibernate-facts-equals-and-hashcode/
             */
        }
    
        /**
         * Test person builder.
         */
        @Test
        public void testPersonBuilder() {
    
            final Long expectedId = new Random().nextLong();
            final Person fromBuilder = Person.builder()
                .id(expectedId)
                .build();
            assertEquals(expectedId, fromBuilder.getId());
    
        }
    
        /**
         * Test person constructor.
         */
        @Test
        public void testPersonConstructor() {
    
            final Long expectedId = new Random().nextLong();
            final Person fromNoArgConstructor = new Person();
            fromNoArgConstructor.setId(expectedId);
            assertEquals(expectedId, fromNoArgConstructor.getId());
        }
    }
    

    Old Version using @Tolerate and @Data:

    Using @Tolerate worked to allow adding a noarg constructor.

    Since you want to use the builder pattern I imagine you want to control visibility of the setter methods.

    The @Data annotation makes the generated setters public, applying @Setter(value = AccessLevel.PROTECTED) to the fields makes them protected.

    Remember to properly override toString, equals, and hashCode. See the following posts by Vlad Mihalcea for details:

    • the-best-way-to-implement-equals-hashcode-and-tostring-with-jpa-and-hibernate
    • how-to-implement-equals-and-hashcode-using-the-jpa-entity-identifier
    • hibernate-facts-equals-and-hashcode
    package lombok.javac.handlers.stackoverflow;
    
    import static org.junit.Assert.*;
    
    import java.util.Random;
    
    import javax.persistence.GenerationType;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Id;
    
    import lombok.AccessLevel;
    import lombok.Builder;
    import lombok.Data;
    import lombok.Setter;
    import lombok.experimental.Tolerate;
    
    import org.junit.Test;
    
    public class So34241718 {
    
        @Builder
        @Data
        public static class Person {
    
            @Id
            @GeneratedValue(strategy = GenerationType.AUTO)
            @Setter(value = AccessLevel.PROTECTED)
            Long id;
    
            @Tolerate
            Person() {}
    
           /* IMPORTANT:
              Override toString, equals, and hashCode as described in these 
              documents:
              - https://vladmihalcea.com/the-best-way-to-implement-equals-hashcode-and-tostring-with-jpa-and-hibernate/
              - https://vladmihalcea.com/how-to-implement-equals-and-hashcode-using-the-jpa-entity-identifier/
              - https://vladmihalcea.com/hibernate-facts-equals-and-hashcode/
              */
        }
    
        @Test
        public void testPersonBuilder() {
    
            Long expectedId = new Random().nextLong();
            final Person fromBuilder = Person.builder()
                .id(expectedId)
                .build();
            assertEquals(expectedId, fromBuilder.getId());
    
        }
    
        @Test
        public void testPersonConstructor() {
    
            Long expectedId = new Random().nextLong();
            final Person fromNoArgConstructor = new Person();
            fromNoArgConstructor .setId(expectedId);
            assertEquals(expectedId, fromNoArgConstructor.getId());
        }
    }
    
    0 讨论(0)
提交回复
热议问题