Lombok

Avoids writing boilerplate code

Features

  • Getter and Setter
  • Constructor
  • Equals and HashCode
  • ToString
  • Builder

Example

@AllArgsContructor @Getter @Setter @ToString
@RequiredArgsConstructor
public class Student {
    @NonNull private int id; // getId(), setId()
    private String name; // getName(), setName()
    private String email; // getEmail(), setEmail()
}

@Builder

For better readability;

@Builder
public class Student {
    private int id;
    private String name;
    private String email;
}

Student student = Student.builder()
    .id(1)
    .name("John")
    .email("john@doe.at")

@SneakyThrows

Wraps checked exceptions in unchecked exceptions

@SneakyThrows
public void read() {
    throw new IOException("File not found");
    // Will be wrapped in UncheckedIOException
}

@EqualsAndHashCode

Generates equals() and hashCode() methods Both because they are related (equals calls hashCode if objects are equal)

@EqualsAndHashCode(callSuper = true)
public class Student extends Person {
    private int id;
    private String name;
    private String email;
}


JDBC Relations

Many-to-Many

public class Movie {
    @ManyToMany
    private Collection<Actor> actors = new HashSet<>();
}
public class Actor {
    @ManyToMany(mappedBy = "actors") 
    private Collection<Movie> movies = new HashSet<>();
}

Persisting

Persisting is the process of storing an object in the database in a way that it can be retrieved later.

public class MovieApp {
    public static void main(String[] args) {
        
        try (EntityManagerFactory emf = Persistence.createEntityManagerFactory("live");
                EntityManager em = emf.createEntityManager()) {

            em.getTransaction().begin();
            Movie movie = new Movie();
            movie.setTitle("Inception");
            em.persist(movie); // write to database
            em.getTransaction().commit();
        }
    }
}

Lazy vs. Eager loading

  • Lazy: Load only when needed
  • Eager: Load immediately
  • Default: Lazy (better performance)
@ManyToMany(fetch = FetchType.LAZY)
private Collection<Actor> actors = new HashSet<>();
@ManyToMany(fetch = FetchType.EAGER)
private Collection<Actor> actors = new HashSet<>();

Equals and HashCode

Problem: Primary key is not available before persisting

Solution: Use business key

@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class Actor {
    @EqualsAndHashCode.Include
    private String name;
}

Cascade/OrphanRemoval

  • Cascade: Propagate operations
  • OrphanRemoval: Remove orphans

(orphans = entities without parent)

class Movie {
    @ManyToMany(cascade = CascadeType.PERSIST)
    private Collection<Actor> actors = new HashSet<>();
}
class Actor {
    @ManyToMany(orphanRemoval = true) // if actor is deleted, remove from movie
    private Collection<Movie> movies = new HashSet<>();
}

@JoinTable

Customize join table

The sample below creates a table movie_actor with columns movie_id and actor_id

@JoinTable(name = "movie_actor", 
    joinColumns = @JoinColumn(name = "movie_id"),
    inverseJoinColumns = @JoinColumn(name = "actor_id"))
private Collection<Actor> actors = new HashSet<>();

Navigation