Skip to main content

One post tagged with "java"

View All Tags

ยท 2 min read

When building out your domain model it is tempting to annotate your entities with @Data.

@Data is a shortcut for @ToString, @EqualsAndHashCode, @Getter on all fields, @Setter on all non-final fields, and @RequiredArgsConstructor 1.

For example:

@Entity
@Data
class Author {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;

private String name;

@OneToMany
private Set<Book> books;

public Set<Book> getBooks() {
/* fetches books from database if books is null */
}
}

Now, lets say you fetch a list of authors from the database and log them. Your logger proceeds to log these authors by calling toString() This will in turn call getBooks() which will do further queries. You have just introduced N+1 queries while fetching author for data you will never use! For this reason, I would mark all associations with @ToString.Exclude

Similar problem arises when you use .equals(other), provided by @EqualsAndHashCode. With entities, equals may be done by comparing id (the primary key). Annotating your primary key attribute with @EqualsAndHashCode.Include, will ensure that only primary key is used for hash code calculation and equals.

caution

Your use-case may vary, write a test for this so others don't assume how .equals(other) is working.

With this advice our entity becomes:

@ToString
@EqualsAndHashCode
@Getter
@Setter
@RequiredArgsConstructor
@Entity
class Author {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@EqualsAndHashCode.Include
private Long id;

private String name;

@ToString.Exclude
@OneToMany
private Set<Book> books;

public Set<Book> getBooks() {
/* fetches books from database if books is null */
}
}