The JPA specification requires that all persistent classes (@Entity
) have a no-arg constructor, public or protected. (note that this is not necessarily true when dealing with some implementation like Hibernate, see this answer).
This is needed because JPA uses the default constructor method to create a bean class using the reflection API. Indeed if your class would contain many constructors then JPA wouldn't know which one to call, this is why it instantiates the class through its no-arg constructor using reflections :
Product.class.newInstance();
which is equivalent to new Product()
(Product.class
is a class literal, it can fail at runtime if the class is not found in the classpath), then, once instantiated, uses fields setters to deal with it.
Then, in Java, a default constructor (no-argument constructor) is automatically generated for a class unless you define other constructors (it only does when you don't provide any other constructor).
So because the compiler automatically creates a default no-arg constructor when no other constructor is defined, only classes that define constructors must also include a no-arg constructor if required by a framework (here JPA). This is why you need to add @NoArgsConstructor
annotation if you add the @AllArgsConstructor
annotation.
Also note that you are using @Data
, which bundles the features of @RequiredArgsConstructor
, which will generate a constructor for all final
or @NonNull
annotated fields (see Lombok documentation). So as you are using only non final nullable fields, it may generate an empty constructor even if you don't add the @NoArgsConstructor
annotation. I have not tested that last case though, I know that it generates an empty constructor when using @RequiredArgsConstructor
directly with non final nullable fields, but I don't know if it works the same when using @Data
.
@Data
also bundles @ToString
, so you don't need to add it again.
I'm personnaly not a fan of using @Data
if I don't need all the bundled annotations, so I usually simply use :
@Entity
@Getter
@Setter
@EqualsAndHashCode
public class Product {
@Id
private int id;
private String name;
private String type;
}
as I often don't use toString()
nor parameterized constructor. It may be more verbose but more meaningful to me.