Spring Boot implementation of JPAstreamer

Mete Ergin
3 min readAug 25, 2021

--

JPAstreamer is a library for expressing JPA queries by the usage of Java Streams. Your application may immediately act on database components using known Stream operators such as filter(), sort(), and map() with just one dependency. As a result, your queries will be more expressive, intuitive, and less likely to contain errors. You can check for best practices of Java Streams from my previous post.

Photo by nousnou iwasaki on Unsplash

For demonstration purposes, I wrote a simple Spring Boot rest project. Also, I added the JPAStreamer library and the Fake Name Generator library which is called Java Faker. On the service layer, I both implemented JPA and JPAStreamer for the same queries.

In order not to get lost in the details I chose the H2 database.

The User entity is used for the base sample data type.

I ran the following code at the bootstrap to get test data which contains 100 random User and saved them to the database. All data can be observed over the H2 console.

For expanding UserRepository I added 7 methods with the usage of Spring Boot JPA implementation syntax.

On service layer, I implemented both JPA Repository and JPA Streamer versions of findAll, findById, findByAge, findByFirstCharacterOfFirstName, findByLessThanAge, findByFirstCharacterOfFirstNameAndAge, findByAgeRange and findMaximumAge methods.

For the controller layer, I wrote a simple IUserController interface that is implemented in both JpaRepositoryUserController and JpaStreamerUserController. Due to I wanted to demonstrate how to get the same results from different rest requests.

When I started the application, 100 random User is saved to the database. So, the demonstration that I will show you would differ from your own results. Let’s try it out;

  1. findAll
curl http://localhost:8080/user/jpa-repository/all
curl http://localhost:8080/user/jpa-streamer/all

On the console, I got the same SQL queries for both requests.

select user0_.id as id1_0_, user0_.age as age2_0_, user0_.first_name as first_na3_0_, user0_.last_name as last_nam4_0_ from user user0_ order by user0_.id asc

And the responses are the same;

[{"id":1,"firstName":"Meri","lastName":"Langworth","age":21},{"id":2,"firstName":"Towanda","lastName":"Runolfsdottir","age":58},{"id":3,"firstName":"Rubin","lastName":"Sauer","age":94},{"id":4,"firstName":"Tia","lastName":"Mante","age":71},....

I will not write long details for the next demonstrations. The process will be the same.

2. findById

curl http://localhost:8080/user/jpa-repository/17
curl http://localhost:8080/user/jpa-streamer/17
Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.first_name as first_na3_0_, user0_.last_name as last_nam4_0_ from user user0_ where user0_.id=?{"id":17,"firstName":"Sang","lastName":"Windler","age":92}

3. findByFirstCharacterOfFirstName

curl http://localhost:8080/user/jpa-repository/findByFirstCharacterOfFirstName/E
curl http://localhost:8080/user/jpa-streamer/findByFirstCharacterOfFirstName/E
select user0_.id as id1_0_, user0_.age as age2_0_, user0_.first_name as first_na3_0_, user0_.last_name as last_nam4_0_ from user user0_ where user0_.first_name like ?[{"id":13,"firstName":"Earleen","lastName":"Cartwright","age":25},{"id":39,"firstName":"Erick","lastName":"Douglas","age":66},{"id":40,"firstName":"Esmeralda","lastName":"Casper","age":41},{"id":71,"firstName":"Elisabeth","lastName":"Emard","age":70}]

4. findByAge

curl http://localhost:8080/user/jpa-repository/findByAge/7
curl http://localhost:8080/user/jpa-streamer/findByAge/7
select user0_.id as id1_0_, user0_.age as age2_0_, user0_.first_name as first_na3_0_, user0_.last_name as last_nam4_0_ from user user0_ where user0_.age=?[{"id":6,"firstName":"Otis","lastName":"Murphy","age":7},{"id":18,"firstName":"Glen","lastName":"Keebler","age":7},{"id":21,"firstName":"Rex","lastName":"Kovacek","age":7}]

5. findByLessThanAge

curl http://localhost:8080/user/jpa-repository/findByLessThanAge/5
curl http://localhost:8080/user/jpa-streamer/findByLessThanAge/5
select user0_.id as id1_0_, user0_.age as age2_0_, user0_.first_name as first_na3_0_, user0_.last_name as last_nam4_0_ from user user0_ where user0_.age<?[{"id":10,"firstName":"Adolfo","lastName":"Roob","age":0},{"id":32,"firstName":"Joeann","lastName":"Stamm","age":0},{"id":50,"firstName":"Hunter","lastName":"Kemmer","age":3},{"id":60,"firstName":"Margy","lastName":"Robel","age":4},{"id":64,"firstName":"Dulcie","lastName":"King","age":0},{"id":98,"firstName":"Belle","lastName":"Moen","age":4}]

6. findByFirstCharacterOfFirstNameAndAge

curl http://localhost:8080/user/jpa-repository/findByFirstCharacterOfFirstNameAndAge/M/4
curl http://localhost:8080/user/jpa-streamer/findByFirstCharacterOfFirstNameAndAge/M/4
select user0_.id as id1_0_, user0_.age as age2_0_, user0_.first_name as first_na3_0_, user0_.last_name as last_nam4_0_ from user user0_ where (user0_.first_name like ?) and user0_.age=?[{"id":60,"firstName":"Margy","lastName":"Robel","age":4}]

7. findByAgeRange

curl http://localhost:8080/user/jpa-repository/findByAgeRange/3/7
curl http://localhost:8080/user/jpa-streamer/findByAgeRange/3/7
select user0_.id as id1_0_, user0_.age as age2_0_, user0_.first_name as first_na3_0_, user0_.last_name as last_nam4_0_ from user user0_ where user0_.age between ? and ?[{"id":22,"firstName":"Wilbert","lastName":"Orn","age":5},{"id":51,"firstName":"Chun","lastName":"Bartell","age":5},{"id":60,"firstName":"Margy","lastName":"Robel","age":4},{"id":89,"firstName":"Les","lastName":"Ortiz","age":5},{"id":98,"firstName":"Belle","lastName":"Moen","age":4}]

8. findMaximumAge

curl http://localhost:8080/user/jpa-repository/findMaximumAge
curl http://localhost:8080/user/jpa-streamer/findMaximumAge
select user0_.id as id1_0_, user0_.age as age2_0_, user0_.first_name as first_na3_0_, user0_.last_name as last_nam4_0_ from user user0_ order by user0_.age desc limit ?{"id":52,"firstName":"Tobias","lastName":"Senger","age":99}

In a nutshell, JPAstreamer allows JPA queries to be written as normal Java Streams utilizing short and simple declarative techniques that are type-safe. Our code will be shorter, less complex, and easier to read and maintain as a result.

All the source codes can be found in my Github repository. Thank you for reading.

--

--

Mete Ergin
Mete Ergin

Responses (2)