Lombok @Builder and JPA Default constructor

前端 未结 8 1858
遇见更好的自我
遇见更好的自我 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:05

    It seems that the annotations order is important here, using the same annotations, but different orders, you can have the code working, or not.

    Here is a non working example:

    @AllArgsConstructor
    @Builder
    @Data
    @Entity
    @EqualsAndHashCode
    @NoArgsConstructor
    @RequiredArgsConstructor
    @Table
    @ToString
    public class Person implements Serializable {
      private String name;
    }
    

    And this is a working example:

    @Builder
    @Data
    @Entity
    @EqualsAndHashCode
    @AllArgsConstructor
    @NoArgsConstructor
    @RequiredArgsConstructor
    @Table
    @ToString
    public class Person implements Serializable {
      private String name;
    }
    

    So be sure to have the @Builder annotation at the very top position, in my case I encountered this error because I wanted to sort annotations alphabetically.

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

    You can also solve it explicitly with @Data @Builder @NoArgsConstructor @AllArgsConstructor combined on the class definition.

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

    To use the following combination

    • lombok
    • JPA
      • CRUD
      • proper @EqualsAndHashCode
    • immutability - public final fields
    • no getters
    • no setters
    • changes via @Builder and @With

    I used:

    //Lombok & JPA
    //https://stackoverflow.com/questions/34241718/lombok-builder-and-jpa-default-constructor
    
    //Mandatory in conjunction with JPA: an equal based on fields is not desired
    @lombok.EqualsAndHashCode(onlyExplicitlyIncluded = true)
    //Mandatory in conjunction with JPA: force is needed to generate default values for final fields, that will be overriden by JPA
    @lombok.NoArgsConstructor(access = AccessLevel.PRIVATE, force = true)
    //Hides the constructor to force usage of the Builder.
    @lombok.AllArgsConstructor(access = AccessLevel.PRIVATE)
    @lombok.ToString
    //Good to just modify some values
    @lombok.With
    //Mandatory in conjunction with JPA: Some suggest that the Builder should be above Entity - https://stackoverflow.com/a/52048267/99248
    //Good to be used to modify all values
    @lombok.Builder(toBuilder = true)
    //final fields needed for imutability, the default access to public - since are final is safe 
    @lombok.experimental.FieldDefaults(makeFinal = true, level = AccessLevel.PUBLIC)
    //no getters and setters
    @lombok.Getter(value = AccessLevel.NONE)
    @lombok.Setter(value = AccessLevel.NONE)
    
    //JPA
    @javax.persistence.Entity
    @javax.persistence.Table(name = "PERSON_WITH_MOTTO")
    //jpa should use field access 
    @javax.persistence.Access(AccessType.FIELD)
    public class Person {
      @javax.persistence.Id
      @javax.persistence.GeneratedValue
      //Used also automatically as JPA
      @lombok.EqualsAndHashCode.Include
      Long id;
      String name;
      String motto;
    }
    
    0 讨论(0)
  • 2020-12-04 11:20

    i solved this using all these annotations:

    @Data
    @Builder
    @AllArgsConstructor(access = AccessLevel.PACKAGE)
    @NoArgsConstructor(access = AccessLevel.PACKAGE)
    
    0 讨论(0)
  • 2020-12-04 11:21

    If the annotations lombok.Tolerate on constructor and javax.validation.constraints.NotNull on some property are used at the same time, sonarqube will mark it as a critical error: PROPERTY is marked "javax.validation.constraints.NotNull" but is not initialized in this constructor.

    If the project uses SpringData with JPA, it can be solved using org.springframework.data.annotation.PersistenceConstructor (Spring annotation, not JPA!)

    Then, in combination with Lombok, annotations will be like this:

    @RequiredArgsConstructor(onConstructor = @__(@PersistenceConstructor))
    

    For Lombok builder you also need to add:

    @Builder
    @AllArgsConstructor
    
    0 讨论(0)
  • 2020-12-04 11:22

    Using @NoArgsConstructor and @AllArgsContructor will help solve the issue of having a default constructor with @Builder.

    e.g

    @Entity 
    @Builder
    @NoArgsConstructor
    @AllArgsContructor
    class Person {
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
    }
    

    This is because @Builder requires all argument constructor and specifying only a default constructor will cause an issue.

    Here is nore explaination: https://github.com/rzwitserloot/lombok/issues/1389#issuecomment-369404719

    0 讨论(0)
提交回复
热议问题