How to get Type-Safe and Intuitive Hibernate/JPA Queries

A large proportion of Java database applications are using Hibernate/JPA to bridge the gap between Java and SQL. Until recently, we were forced to mix Java and JPQL or to use complex imperative criteria builders to create database queries. Both of these methods are inherently neither type-safe nor very intuitive.  The newly launched  open-source library JPAstreamer addresses these issues by allowing you to express Hibernate/JPA queries using Java Streams. This means we can avoid any impedance mismatches between JPQL/HQL and Java and get full type-safety. In this article, I will show you how to put Java Stream queries to work in your application using JPAstreamer.

JPAstreamer in a Nutshell

As mentioned, JPAstreamer allows JPA queries to be expressed as standard Java Streams using short and concise, type-safe declarative constructs. This makes our code shorter, less complex, and easier to read and maintain. Best of all, we can stick to using only Java code without needing to mix it with SQL/JPQL or other language constructs/DSL.

In short, we can query a database like this:

A Stream Annoyance

Of course we all love the creamy, functional goodness that oozed from Java 8. And I'm certainly no imperativist, like those in this Java video.

But one thing bothers me.

Java Joy: Combining Predicates

Combining predicates in Java brings developers lots of joy.

In Java, we can use a Predicate to test if something is true or false. This is especially useful when we use the filter method of the Java Stream API.

You may also like: Towards More Functional Java Using Lambdas as Predicates

We can use lambda expressions to define our Predicate or implement the Predicate interface. If we want to combine different Predicate objects, we can use the or, and, and negate methods of the Predicate interfaces. These are default methods of the interface and will return a new Predicate.

Java: An Optional Implementation of Optional

The class java.util.Optional is implemented as a single immutable concrete class that internally handles two cases; one with an element and one without. Wouldn't it have been a better choice to let Optional be an interface and have two different implementations implement that interface instead? After all, that is what we generally are taught to do in an object-oriented language.

In this article, we will learn about some of the potential arguments for the current Optional implementation. We will also learn why Streams are implemented in a different way, enabling Streams to be obtained from files or even database tables.