DEV Community

Jonathan Tavares
Jonathan Tavares

Posted on

How to use JPA API Specification?

Hey, this is my first article here. I hope that I'll be able to post content about technology more consistently from now on.

I've chosen to bring you an advanced JPA 2 topic: the Specification API.

Specification was a concept that Eric Evans brought up in his book Domain Driven Design(DDD). Based on this, JPA brings this concept as a set of interfaces that facilitate the reuse of predicates, using the Criteria API. That's it, simples as that.

Let's look an example:

We have a book model with id, author, title, isbn and publication year.

@Entity
@Data
public class Book {
@Id
private Integer id;
private String author;
private String title;
private String isbn;
private Integer publicationYear;
}
view raw Book.java hosted with ❤ by GitHub

and We have a book repository interface that extends JpaSpecificationExecutor

public interface BookRepository extends JpaRepository<Book, Integer>, JpaSpecificationExecutor<Book> {
}

The JpaSpecificationExecutor provides two methods:

List<T> findAll(Specification<T> specification);
Page<T> findAll(Specification<T> specification, Pageable pageable);

Now to build our query, We can define the class that implements the Specification interface.

public class BookSpecifications {
public static Specification<Book> booksByAuthor(String authorName) {
return (root, query, cb) -> cb.like(cb.lower(root.get(Book_.author)), "%" + authorName.toLowerCase() + "%");
}
}

With this static method booksByAuthor, we can use this specification to filter for all books that have an author in common. Let's see how simple it is below:

bookRepository.findAll(booksByAuthor("George R. R. Martin"));

One aspect of the specification that makes it more interesting is the fact that we can combine the queries. Let's look an example:

bookRepository.findAll(where(booksByAuthor("George R. R. Martin")).and(booksByPublicationYear(1996)));

And the specification class would look like this:

public class BookSpecifications {
public static Specification<Book> booksByAuthor(String authorName) {
return (root, query, cb) -> cb.like(cb.lower(root.get(Book_.author)), "%" + authorName.toLowerCase() + "%");
}
public static Specification<Book> booksByPublicationYear(int publicationYear) {
return (root, query, cb) -> cb.equal(root.get(Book_.publicationYear), publicationYear);
}
}

That's it. Thank you very much for reading this content. I usually bring content with a more hands-on approach and if something wasn't so clear, feel free to comment and suggest improvements.

If you want to know more about this content, I recommend the official documentation:
JPA Specifications

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (1)

Collapse
 
saladlam profile image
Salad Lam

Hello Jonathan,

Thank you for your sharing. I also wrote something on Specification interface and may inspire you on how to use it in new ways.

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay