I\'m using project Lombok together with Spring Data JPA.
Is there any way to connect Lombok @Builder
with JPA default constructor?
Code:
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.
You can also solve it explicitly with @Data @Builder @NoArgsConstructor @AllArgsConstructor
combined on the class definition.
To use the following combination
@EqualsAndHashCode
@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;
}
i solved this using all these annotations:
@Data
@Builder
@AllArgsConstructor(access = AccessLevel.PACKAGE)
@NoArgsConstructor(access = AccessLevel.PACKAGE)
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
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