views:

58

answers:

2

Hello there,

I'm rewriting some messy code that manages a database, and saw that the original programmer created a class mapped to the database like so:

(I've removed unnecessary code that has no purpose in this question)

@Entity
@Data
@EqualsAndHashCode(callSuper = false, of = { "accessionCode", "header", "date" })
@SuppressWarnings("PMD.UnusedPrivateField")
public class PDBEntry implements Serializable {
    @Id
    @NaturalId
    @NotEmpty
    @Length(max = 4)
    private String accessionCode;

    @NaturalId
    @NotEmpty
    private Date date;

    @NaturalId
    // We allow for the header to be 'null'
    private String header;

    private Boolean isValidDssp;

    @Temporal(TemporalType.TIMESTAMP)
    private Date lastUpdated = new Date(System.currentTimeMillis());

    protected PDBEntry(){}

    public PDBEntry(String accessionCode, String header, Date date){
        this.accessionCode = accessionCode;
        this.header = header;
        this.date = date;
    }
}

I am still a beginner at Hibernate and using Lombok, but wouldn't this do the same thing and wouldn't Lombok automatically create the needed constructor for you?

@Entity
@Data
@SuppressWarnings("PMD.UnusedPrivateField")
public class PDBEntry implements Serializable {
    @Id
    @NaturalId
    @NotEmpty
    @NonNull
    @Length(max = 4)
    private String accessionCode;

    @NaturalId
    @NotEmpty
    @NonNull
    private Date date;

    @NaturalId
    // We allow for the header to be 'null'
    private String header;

    private Boolean isValidDssp;

    @Temporal(TemporalType.TIMESTAMP)
    private Date lastUpdated = new Date(System.currentTimeMillis());
}

Also, the original programmer of this code says he allows for the header to be 'null', yet he explicitly created a constructor that needs a value for header. Am I missing something or is this a bit contradictory?

+1  A: 

That bit is contradictory you're right. I've not used Lombok before but with hibernate if you want to be able to create a bean and persist you need the default constructor as given above as far I was aware. It uses Constructor.newInstance() to instantiate new objects.

Here is some hibernate documentation which goes into more detail.

Hibernate Documentation

DeliveryNinja
The @Data annotation right above the class def will create this default constructor as far as I know, and from what I've learned so far the @NonNull annotations above the fields will cause Lombok to make these fields parameters in that constructor so that you have to give values for them, and will also check whether they are null. But since I'm new to this I was wondering if it's just me or that the original programmer made a few small mistakes here.
FinalArt2005
+2  A: 

Have a look at @NoArgsConstructor, @RequiredArgsConstructor, @AllArgsConstructor.

The constructor behavior of @Data is like @RequiredArgsConstructor:

@RequiredArgsConstructor generates a constructor with 1 parameter for each field that requires special handling. All final fields get a parameter, as well as any fields that are marked as @NonNull that aren't initialized where they are declared.

Given that none of your fields are either final or @NonNull, this will result in a no-argument constructor. However, this is not the most expressive way to achieve this behavior.

What you'll probably want in this case is a @NoArgsConstructor (optionally combined with a @AllArgsConstructor), to clearly communicate the intended behavior, as is also indicated in the documentation:

Certain java constructs, such as hibernate and the Service Provider Interface require a no-args constructor. This annotation is useful primarily in combination with either @Data or one of the other constructor generating annotations.

Tim
Yes, I read about the @RequiredArgsConstructor, but since it's standard in @Data I didn't add it. My question was whether I used the annotations correctly since the original programmer did use Lombok but didn't use @NonNull annotations, but instead used explicit constructors. You say none of my fields are @NonNull, but look closely in my code (the second box), I annotated the accessionCode and date fields with @NonNull. Now since Hibernate indeed seems to require a no-args constructor, would this be a good style? @Data@NoArgsConstructor(access = AccessLevel.PROTECTED)@RequiredArgsConstructor
FinalArt2005
Yup, that would be the way to go..
Tim
Ok, just for anyone that is also starting to use Lombok, I just heard that @RequiredArgsConstructor isn't very robust, it takes the order of the fields in your class to build the constructor, so if someone else changes this order your code that calls the constructor stops working, so turns out the explicit constructor is still the better choice. The @NoArgsConstructor(access = AccessLevel.PROTECTED) however does seem to be useful if you're using Hibernate. Thanks everybody for your help.
FinalArt2005