Multiline String literals with Java Text Blocks
Imagine having a tool that can automatically detect JPA and Hibernate performance issues. Wouldn’t that be just awesome?
Well, Hypersistence Optimizer is that tool! And it works with Spring Boot, Spring Framework, Jakarta EE, Java EE, Quarkus, or Play Framework.
So, enjoy spending your time on the things you love rather than fixing performance issues in your production system on a Saturday night!
Introduction
In this article, show you how the new Java Text Blocks can help you increase the readability of JPQL, SQL queries, or JSON string values.
Back in 2005, I was developing a .NET project and really liked the C# Verbatim String Literal feature since it allows you to write a multiline string value without having to concatenate each individual line.
The Java 13 Text Blocks feature now offers the possibility of creating a multiline Java String
values.
Take a look at how the new #Java Text Blocks can help you increase the readability of JPQL, SQL queries, or JSON string values.https://t.co/wBKLIyb0XF pic.twitter.com/H6VOKW4szH
— Java (@java) March 10, 2020
Java Text Blocks for JPQL or SQL Queries
Whether you are executing a JPQL or an SQL query, without Text Blocks, this is how a query execution would look like when using JPA:
List<Tuple> posts = entityManager .createNativeQuery( "SELECT *\n" + "FROM (\n" + " SELECT *,\n" + " dense_rank() OVER (\n" + " ORDER BY \"p.created_on\", \"p.id\"\n" + " ) rank\n" + " FROM (\n" + " SELECT p.id AS \"p.id\",\n" + " p.created_on AS \"p.created_on\",\n" + " p.title AS \"p.title\",\n" + " pc.id as \"pc.id\",\n" + " pc.created_on AS \"pc.created_on\",\n" + " pc.review AS \"pc.review\",\n" + " pc.post_id AS \"pc.post_id\"\n" + " FROM post p\n" + " LEFT JOIN post_comment pc ON p.id = pc.post_id\n" + " WHERE p.title LIKE :titlePattern\n" + " ORDER BY p.created_on\n" + " ) p_pc\n" + ") p_pc_r\n" + "WHERE p_pc_r.rank <= :rank\n", Tuple.class) .setParameter("titlePattern", "High-Performance Java Persistence %") .setParameter("rank", 5) .getResultList();
For readability, we don’t want to display the entire query on a single line, so we need to use a multiline String
. Prior to Java 13, you’d either use String
concatenation or a StringBuilder
in order to create a multiline String
.
Starting with Java 13, you can use Text Blocks, and, you don’t even have to manually transform the legacy multiline String
concatenation to the new multiline text block format. With IntelliJ IDEA, you can press ALT + ENTER
and choose the Replace with text block
option:
After applying the Replace with text block
action, this is how your query can look like:
List<Tuple> posts = entityManager .createNativeQuery(""" SELECT * FROM ( SELECT *, dense_rank() OVER ( ORDER BY "p.created_on", "p.id" ) rank FROM ( SELECT p.id AS "p.id", p.created_on AS "p.created_on", p.title AS "p.title", pc.id as "pc.id", pc.created_on AS "pc.created_on", pc.review AS "pc.review", pc.post_id AS "pc.post_id" FROM post p LEFT JOIN post_comment pc ON p.id = pc.post_id WHERE p.title LIKE :titlePattern ORDER BY p.created_on ) p_pc ) p_pc_r WHERE p_pc_r.rank <= :rank """, Tuple.class) .setParameter("titlePattern", "High-Performance Java Persistence %") .setParameter("rank", 5) .getResultList();
The SQL query is way more readable when using Java Text Blocks.
Java Text Blocks for JSON objects
Another place where Java Text Blocks are really useful is when you need to represent JSON, XML, or HTML in your Java code.
Consider the following Book
entity that has a JSON properties
attribute:
entityManager.persist( new Book() .setId(1L) .setIsbn("978-9730228236") .setProperties( "{" + " \"title\": \"High-Performance Java Persistence\"," + " \"author\": \"Vlad Mihalcea\"," + " \"publisher\": \"Amazon\"," + " \"price\": 44.99," + " \"reviews\": [" + " {" + " \"reviewer\": \"Cristiano\", " + " \"review\": \"Excellent book to understand Java Persistence\", " + " \"date\": \"2017-11-14\", " + " \"rating\": 5" + " }," + " {" + " \"reviewer\": \"T.W\", " + " \"review\": \"The best JPA ORM book out there\", " + " \"date\": \"2019-01-27\", " + " \"rating\": 5" + " }," + " {" + " \"reviewer\": \"Shaikh\", " + " \"review\": \"The most informative book\", " + " \"date\": \"2016-12-24\", " + " \"rating\": 4" + " }" + " ]" + "}" ) );
When transforming the properties
attribute to a text block, the JSON object is unarguably much more readable:
entityManager.persist( new Book() .setId(1L) .setIsbn("978-9730228236") .setProperties(""" { "title": "High-Performance Java Persistence", "author": "Vlad Mihalcea", "publisher": "Amazon", "price": 44.99, "reviews": [ { "reviewer": "Cristiano", "review": "Excellent book to understand Java Persistence", "date": "2017-11-14", "rating": 5 }, { "reviewer": "T.W", "review": "The best JPA ORM book out there", "date": "2019-01-27", "rating": 5 }, { "reviewer": "Shaikh", "review": "The most informative book", "date": "2016-12-24", "rating": 4 } ] } """ ) );
Cool, right?
If you enjoyed this article, I bet you are going to love my Book and Video Courses as well.
Conclusion
Finally, Java has a proper solution to multiline String
values. I have switched my High-Performance Java Persistence GitHub repository, as well as the training material for the High-Performance SQL workshop, and the results are spectacular.
Considering that Java 13, 14, 15, and 16 are not LTS (Long-Term Support) releases, most Java projects will probably wait for Java 17 to start adopting this feature. But, for a greenfield project that’s going to launch in production after September 2021 when Java 17 is supposed to be released, it might be a good idea to start the development using Java 14.
