DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Express Hibernate Queries as Type-Safe Java Streams
  • The Ultimate Guide on DB-Generated IDs in JPA Entities
  • Apache Cassandra Horizontal Scalability for Java Applications [Book]
  • Java EE 6 Pet Catalog with GlassFish and MySQL

Trending

  • Detecting Advanced Persistent Threats Using Behavioral Analytics and Log Correlation
  • Introduction to Retrieval Augmented Generation (RAG)
  • Leveraging Apache Flink Dashboard for Real-Time Data Processing in AWS Apache Flink Managed Service
  • From APIs to Actions: Rethinking Back-End Design for Agents
  1. DZone
  2. Data Engineering
  3. Databases
  4. How to get Type-Safe and Intuitive Hibernate/JPA Queries

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

Learn how to use standard Java streams which automatically convert themselves to Hibernate/JPA Queries.

By 
Per-Åke Minborg user avatar
Per-Åke Minborg
·
Julia Gustafsson user avatar
Julia Gustafsson
·
Updated Oct. 22, 20 · Tutorial
Likes (7)
Comment
Save
Tweet
Share
10.0K Views

Join the DZone community and get the full member experience.

Join For Free
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:

Java
 




x


 
1
jpaStreamer.stream(Film.class)
2
    .sorted(Film$.length.reversed())
3
    .limit(15)
4
    .map(Film$.title)
5
    .forEach(System.out::println);



This prints the title of the 15 longest films in the database.

OSS License

JPAstreamer is using the same license as Hibernate (LGPL). This makes it easy to use in existing Hibernate projects. JPAstreamer also works with other JPA providers such as EclipseLink, OpenJPA, TopLink etc.

Installation

Installing JPAstreamer entails just adding a single dependency in your Maven/Gradle configuration file as described here. For example, Maven users add the following dependency:

XML
 




x


 
1
 <dependency> 
2
     <groupId>com.speedment.jpastreamer</groupId>
3
     <artifactId>jpastreamer-core</artifactId>
4
     <!-- Make sure to use the latest version -->
5
     <version>0.1.8</version>
6
 </dependency>



Let's have a look at how JPAstreamer fits in an existing application.

Example Database and JPA Entities

In the examples below, we are using JPAstreamer to query the "Sakila" example database that is available for download directly from Oracle or as a Docker instance.

This is how you install and run the example database using Docker:

Shell
 




xxxxxxxxxx
1


 
1
$ docker pull restsql/mysql-sakila
2
$ docker run -d --publish 3306:3306 --name mysqld restsql/mysql-sakila



We will also be relying on JPA entities like the Film-class partly shown here:

Java
 




xxxxxxxxxx
1
24


 
1
@Entity
2
@Table(name = "film", schema = "sakila")
3
public class Film implements Serializable {
4
 
           
5
    @Id
6
 
           
7
    @GeneratedValue(strategy = GenerationType.IDENTITY)
8
    @Column(name = "film_id", nullable = false, updatable = false, columnDefinition = "smallint(5)")
9
    private Integer filmId;
10
 
           
11
    @Column(name = "title", nullable = false, columnDefinition = "varchar(255)")
12
    private String title;
13
 
           
14
    @Column(name = "description", nullable = false, columnDefinition = "text")
15
    private String description;
16
 
           
17
    @ManyToMany(cascade = CascadeType.ALL)
18
    @JoinTable(
19
        name = "film_actor",
20
        joinColumns = @JoinColumn(name = "film_id") ,
21
        inverseJoinColumns = @JoinColumn(name = "actor_id") 
22
    )
23
    private List<Actor>;



The complete code in this article is open-sourced and available here.

JPAstreamer — Printing the Longest Films

Here is a complete example of how we can use JPAstreamer to create a query that prints out the length and title of the 15 longest films in the database:

Java
 




xxxxxxxxxx
1
15
8
10


 
1
public class LongestFilms {
2
 
3
  public static void main(String[] args) {
4
      
5
        final JPAStreamer jpaStreamer = JPAStreamer.of("sakila");
6
      
7
        jpaStreamer.stream(Film.class)
8
            .sorted(Film$.length.reversed())
9
            .limit(15)
10
            .map(f -> String.format("%3d %s", f.getLength(), f.getTitle()))
11
            .forEach(System.out::println);
12
    
13
        jpaStreamer.close();
14
    }
15
}



This will print:

Plain Text
 




xxxxxxxxxx
1
14


 
1
185 SOLDIERS EVOLUTION
2
185 GANGS PRIDE
3
185 SWEET BROTHERHOOD
4
185 CHICAGO NORTH
5
185 HOME PITY
6
185 POND SEATTLE
7
185 CONTROL ANTHEM
8
185 DARN FORRESTER
9
185 WORST BANGER
10
184 SMOOCHY CONTROL
11
184 SONS INTERVIEW
12
184 SORORITY QUEEN
13
184 MOONWALKER FOOL
14
184 THEORY MERMAID



As can be seen, queries are simple, concise, completely type-safe and follow the Java Stream standard API. No need to learn new stuff.

The code above will create the following SQL (shortened for brevity):

MySQL
 




xxxxxxxxxx
1


 
1
select
2
    film0_.film_id as film_id1_1_,
3
    film0_.length as length4_1_,
4
    film0_.title as title10_1_,
5
    /* more columns */
6
from
7
    film film0_ 
8
order by
9
    film0_.length desc limit ?



This means that most of the Java stream is actually executed on the database side. It is only the map() and forEach() operations (which cannot easily be translated to SQL) that are executed in the JVM. This is really cool!

Pre-Joining Columns

To avoid the "SELECT N + 1" problem, it is possible to configure streams to join in columns eagerly by providing a configuration object like this:

Java
 




xxxxxxxxxx
1


 
1
StreamConfiguration configuration = StreamConfiguration.of(Film.class)
2
    .joining(Film$.actors)
3
    .joining(Film$.language);
4
 
           
5
jpaStreamer.stream(configuration) 
6
    .filter(Film$.rating.in("G", "PG"))
7
    .forEach(System.out::println);



This will create a Hibernate join under the hood and will only render a single SQL query where all the Film fields "List<Artist> artists" and "Language language" will be populated on the fly:

Conclusion

In this article, I have shown how you can avoid impedance mismatches between JPQL/HQL in Hibernate/JPA using the open-source library JPAstreamer. The Stream API allows you to compose type-safe and expressive database queries in standard Java without compromising the application performance.

The background to JPAStreamer is that we have developed the stream-based ORM-tool Speedment, and we have come across many developers that want to use Java streams but are constrained to use Hibernate in their applications. Therefore, we have now developed JPAstreamer, a JPA/Hibernate extension that handles Java Stream queries without the need to change the existing codebase.

Take JPAStreamer for a spin and let me know what you like/dislike by dropping a message on Gitter!

Resources

  • GitHub: github.com/speedment/jpa-streamer
  • Homepage: jpastreamer.org
  • Documentation: https://speedment.github.io/jpa-streamer/jpa-streamer/0.1.8/introduction/introduction.html
  • Gitter Support Chat for questions and feedback: gitter.im/jpa-streamer
Database Java (programming language) Open source Stream (computing) sql application MySQL Hibernate Type safety

Published at DZone with permission of Per-Åke Minborg. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Express Hibernate Queries as Type-Safe Java Streams
  • The Ultimate Guide on DB-Generated IDs in JPA Entities
  • Apache Cassandra Horizontal Scalability for Java Applications [Book]
  • Java EE 6 Pet Catalog with GlassFish and MySQL

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook