Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
3.0k views
in Technique[技术] by (71.8m points)

java - How do I create a safe Lombok JPA entity?

I have an @Entity with 20 fields including the index and a timestamp updated by Hibernate:

@Entity
public class MyEntity {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;
  @UpdateTimestamp
  private LocalDateTime updatedTime;
  private String ....
  private String ....

I have a default constructor for Hibernate and a secondary constructor to set everything but the id and updatedTime.

I don't need (or want) setters for id or updatedTime because I only want Hibernate to set them, and it does that with reflection.

I wanted to try out Lombok to see if I could avoid a lot of boilerplate involved here but @Data adds both getters and setters and doesn't create the same constructors.

I'm also concerned that Lomboks generated equals/hashCode and toString methods can cause subtle problems with Hibernate.

This will mean I will have to use a combination of the other Lombok annotations to do this.

How do I safely create an Entity using Lombok like this?
Am I going to have to use a mixture of annotations and manual methods?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Some lombok annotations like @EqualsAndHashCode and @ToString have Exclude option. But neither @Data nor @AllArgsConstructor has a similar option. But @Data generates setters for all fields for which a setter is not already defined. So you would define a setter as below for the required fields, which does nothing.

private void setId(Long id) {
    // Do nothing
}

Instead of the @AllArgsConstructor, you could either use @RequiredArgsConstructor, but annotate all the fields to be in the constructor with @NonNull (or the field should be final). Refer this answer for RequiredArgsConstructor.

My suggested approach : Another way would be to use @Builder annotation along with @AllArgsConstructor(access = AccessLevel.PRIVATE). (NOTE : Builder by default adds a private all argument constructor, but this is done only if there are no other constructors. But in your case, a default constructor exists and you need to explicitly mention the all args annotation.)

This would prevent the use of the constructor from outside, but at the same time allow you to create objects using the builder. At this point, you could set the values to id and updateTime using the builder. To prevent this you need to add the below code as well.

public static class MyEntityBuilder {
    // access is restricted using
    // these private dummy methods.

    private MyEntityBuilder id(Long id) { 
        return this; 
    }

    private MyEntityBuilder updateTime(LocalDateTime time) { 
        return this; 
    }

}

So, even though it is not possible to achieve your requirement directly, you could do so by adding two dummy setter methods and another two dummy methods within the builder class.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...