Defining Entity Listener Class Via @EntityListeners

This application is a sample of using the JPA @MappedSuperclass and @EntityListeners with JPA callbacks.

Key points:

  • the base class ,Book, is not an entity, it can be abstract, and is annotated with @MappedSuperclass and @EntityListeners(BookListener.class)
  • BookListener defines JPA callbacks (e.g., @PrePersist)
  • subclasses of the base class are mapped in tables that contains columns for the inherited attributes and for their own attibutes
  • when any entity that is a subclass of Book is persisted, loaded, updated, etc the corresponding JPA callbacks are called

Author.java

@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
@Entity
public class Author implements Serializable {
private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;
private String genre;
private int age;
}

Book.java

@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
@MappedSuperclass
@EntityListeners(BookListener.class)
public abstract class Book implements Serializable {

private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String title;
private String isbn;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "author_id")
private Author author;
}

EBook.java

@AllArgsConstructor
@NoArgsConstructor
@Data
@Entity
public class Ebook extends Book implements Serializable {
private static final long serialVersionUID = 1L;
private String format;
}

Paperback.java

@AllArgsConstructor
@NoArgsConstructor
@Data
@Entity
public class Paperback extends Book implements Serializable {

private static final long serialVersionUID = 1L;

private String sizeIn;
private String weightLbs;
}

BookListener.java

public class BookListener {

@PrePersist
void onPrePersist(Book book) {
System.out.println("BookListener.onPrePersist(): " + book);
}

@PostPersist
void onPostPersist(Book book) {
System.out.println("BookListener.onPostPersist(): " + book);
}

@PostLoad
void onPostLoad(Book book) {
System.out.println("BookListener.onPostLoad(): " + book);
}

@PreUpdate
void onPreUpdate(Book book) {
System.out.println("BookListener.onPreUpdate(): " + book);
}

@PostUpdate
void onPostUpdate(Book book) {
System.out.println("BookListener.onPostUpdate(): " + book);
}

@PreRemove
void onPreRemove(Book book) {
System.out.println("BookListener.onPreRemove(): " + book);
}

@PostRemove
void onPostRemove(Book book) {
System.out.println("BookListener.onPostRemove(): " + book);
}
}

AuthorRepository.java

@Repository
public interface AuthorRepository extends JpaRepository<Author, Long> {

@Transactional(readOnly=true)
Author findByName(String name);
}

EbookRepository.java

@Repository
public interface EbookRepository extends JpaRepository<Ebook, Long>{

@Transactional(readOnly = true)
Ebook findByTitle(String title);

@Transactional(readOnly = true)
@Query("SELECT e FROM Ebook e JOIN FETCH e.author")

Ebook fetchByAuthorId(Long id);
}

PaperbackRepository.java

@Repository
public interface PaperbackRepository extends JpaRepository<Paperback, Long> {

@Transactional(readOnly = true)
Paperback findByTitle(String title);

@Transactional(readOnly = true)
@Query("SELECT e FROM Paperback e JOIN FETCH e.author")

Paperback fetchByAuthorId(Long id);
}

BookstoreService.java

@Service
public class BookstoreService {
@Autowired
private AuthorRepository authorRepository;
@Autowired
private PaperbackRepository paperbackRepository;
@Autowired
private EbookRepository ebookRepository;

@Transactional
public void persistAuthorWithBooks() {
Author author = new Author();
author.setName("Alicia Tom");
author.setAge(38);
author.setGenre("Anthology");

Paperback paperback = new Paperback();
paperback.setIsbn("002-AT");
paperback.setTitle("The beatles anthology");
paperback.setSizeIn("7.5 x 1.3 x 9.2");
paperback.setWeightLbs("2.7");
paperback.setAuthor(author);

Ebook ebook = new Ebook();
ebook.setIsbn("003-AT");
ebook.setTitle("Anthology myths");
ebook.setFormat("kindle");
ebook.setAuthor(author);

authorRepository.save(author);
paperbackRepository.save(paperback);
ebookRepository.save(ebook);
}

@Transactional
public void fetchAndRemovePaperback() {
Paperback paperback = paperbackRepository.findByTitle("The beatles anthology");
paperbackRepository.delete(paperback);
}

@Transactional
public void fetchAndRemoveEbook() {
Ebook ebook = ebookRepository.findByTitle("Anthology myths");
ebookRepository.delete(ebook);
}
}

application.properties

spring.datasource.url=jdbc:mysql://localhost:3306/bookstoredb?createDatabaseIfNotExist=true&useSSL=false
spring.datasource.username=root
spring.datasource.password=root

spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect

spring.jpa.open-in-view=false

#logging.level.org.hibernate.type.descriptor.sql=TRACE

MainApp.java

@SpringBootApplication
public class MainApplication {

@Autowired
private BookstoreService bookstoreService;

public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}

@Bean
public ApplicationRunner init() {
return args -> {
System.out.println("\n\npersistAuthorWithBooks():");
bookstoreService.persistAuthorWithBooks();

System.out.println("\n\nfetchAndRemovePaperback():");
bookstoreService.fetchAndRemovePaperback();

System.out.println("\n\nfetchAndRemoveEbook():");
bookstoreService.fetchAndRemoveEbook();
};
}
}

Console.output

persistAuthorWithBooks():
Hibernate: insert into author (age, genre, name) values (?, ?, ?)
BookListener.onPrePersist(): Paperback(sizeIn=7.5 x 1.3 x 9.2, weightLbs=2.7)
Hibernate: insert into paperback (author_id, isbn, title, size_in, weight_lbs) values (?, ?, ?, ?, ?)
BookListener.onPostPersist(): Paperback(sizeIn=7.5 x 1.3 x 9.2, weightLbs=2.7)
BookListener.onPrePersist(): Ebook(format=kindle)
Hibernate: insert into ebook (author_id, isbn, title, format) values (?, ?, ?, ?)
BookListener.onPostPersist(): Ebook(format=kindle)

fetchAndRemovePaperback():
Hibernate: select paperback0_.id as id1_2_, paperback0_.author_id as author_i6_2_, paperback0_.isbn as isbn2_2_, paperback0_.title as title3_2_, paperback0_.size_in as size_in4_2_, paperback0_.weight_lbs as weight_l5_2_ from paperback paperback0_ where paperback0_.title=?
BookListener.onPostLoad(): Paperback(sizeIn=7.5 x 1.3 x 9.2, weightLbs=2.7)
BookListener.onPreRemove(): Paperback(sizeIn=7.5 x 1.3 x 9.2, weightLbs=2.7)
Hibernate: delete from paperback where id=?
BookListener.onPostRemove(): Paperback(sizeIn=7.5 x 1.3 x 9.2, weightLbs=2.7)

fetchAndRemoveEbook():
Hibernate: select ebook0_.id as id1_1_, ebook0_.author_id as author_i5_1_, ebook0_.isbn as isbn2_1_, ebook0_.title as title3_1_, ebook0_.format as format4_1_ from ebook ebook0_ where ebook0_.title=?
BookListener.onPostLoad(): Ebook(format=kindle)
BookListener.onPreRemove(): Ebook(format=kindle)
Hibernate: delete from ebook where id=?
BookListener.onPostRemove(): Ebook(format=kindle)

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store