Sitemap
Viraj Shetty

Viraj Shetty

Coder • Writer • Instructor • YouTube: https://www.youtube.com/@viraj_shetty • LinkedIn: https://www.linkedin.com/in/shettyviraj/

Java String Templates — A Better Interpolation

6 min readDec 3, 2023

--

NOTE — This Preview feature has been shelved and will not go to Production. Read only for curiosity.

As part of software development, Java Developers regularly construct strings by combining various objects and expressions. Java Language provides many mechanisms to do so but none of them are convenient. This article talks about a proposed Java 21 JSR 430 — which attempts to rectify this inconvenience.

Press enter or click to view image in full size
Photo by Thought Catalog on Unsplash

Also check out my YouTube Channel at https://www.youtube.com/@viraj_shetty and subscribe for quality software content.

String construction techniques

Here are some of the ways that Java provides for String construction. All of these methods are relatively difficult to read and are verbose.

// String concatenation
var l = "My name is " + name + ". My age is " + age + "."

// String format method
var l = String.format("My name is %s. My age is %d.", name, age)

// String formatted method
var l = "My name is %s. My age is %d.".formatted(name, age);

// Message Format
var l = MessageFormat.format("My name is {0}. My age is {1}.", name, age);

Many of the current programming languages like Groovy or Javascript, do offer a technique called String Interpolation which can be quite expressive. With this technique, the variables or expressions are embedded inside the string itself and this improves the expressiveness. At run time, the variables and expressions are evaluated and replaced with their “stringified” values.

Here are a few examples of String Interpolation using Groovy and Javascript.

// String Interpolation using Groovy 
"My name is $name. My age is $age"

// String Interpolation using Javascript
`My name is ${name}. My age is ${age}`

String Template Basics

With Java 21, Oracle has introduced a Preview feature called String Templates which brings interpolation to Java and much more. String Templates can be considered as a superior form of String interpolation.

Let’s start with a simple example. Here’s an equivalent example of interpolation in Java.

String line = STR."My name is \{name}. My age is \{age}." ;

The expression on the right side of the equals(=) sign, is called the Template Expression. We will come to why this syntax looks so strange because there is more to this than meets the eye.

We can also use Template Expressions with multi line strings with a syntax which looks similar to Java Text Blocks.

// Multiline Template Expression
String line = STR."""
My name is \{name}.
My age is \{age}.
""" ;

Multiline strings can be useful in expressing SQL statements, XML blocks or JSON blocks. An example is shown below.

// Create JSON Block using String Templates
String line = STR."""
{
"name" : "\{name}",
"age" : \{age}
}
"""

Template Processors

Java String Templates are more powerful than just String Interpolation. The syntax of the Template Expression is composed of 3 parts.

  • Template Processor (STR) — The Template Processor is a class implementing StringTemplate.Processor interface and is directly responsible for the conversion of String Template to the final output.
  • Character DOT (.)
  • String Template — The String Template is the string containing the variables and expressions. The StringTemplate class directly represents the String template. With this String Template, the static parts are called fragments and the dynamic parts are filled by values.

We can think about this as the String template being evaluated at runtime by the Template Processor. There are several inbuilt Template Processors available in Java.

STR is one of the inbuilt Template Processors that can be used to evaluate the String Template. Apart from STR, there are two other Template Processors available — FMT and RAW.

FMT performs String interpolation but it also interprets format specifiers which appear to the left of embedded expressions. Here’s an example of using FMT for creating a text report.

// FMT also interprets format identifiers
String report = FMT."""
Name Age
======================
%-14s\{name} %-12d\{age}
%-14s\{name1} %-12d\{age1}
""";

Both of these template processors — STR and FMT — finally outputs a String but its not necessary to be a string.

Get Viraj Shetty’s stories in your inbox

Join Medium for free to get updates from this writer.

RAW is another inbuilt TemplateProcessor which simply returns the StringTemplate object. Using the StringTemplate object, we can extract the fragments (static texts) and the values (user provided values) of the String Template. Notice that the output below (tmpl field) from this Template Expression is an Object and not a String.

// Template Processor RAW is used to 
// return the StringTemplate object
StringTemplate tmpl
= RAW."My name is \{name}. My age is \{age}."

// Extract the fragments and values
List<String> fragments = tmpl.fragments();
List<Object> values = tmpl.values();

Custom Template Processor

As Java Developers, we can create our own Template Processors. For that, our Template Processor class must implement the interface StringTemplate.Processor as well — Just like Inbuilt Templates.

The StringTemplate.Processor interface looks like below

interface Processor<R,E extends Throwable> {

R process(StringTemplate stringTemplate)
throws E;

// Static methods not shown

}

You can see that the Processor interface is very general and the process() method can return any Type — not necessarily String.

You can think about the template expression as a transformation of the String Template to any Type by going through the process() method of the Processor.

String line = STR."My name is \{name}. My age is \{age}." ;

// Above code is equivalent to code below
var tmpl = RAW."My name is \{name}. My age is \{age}.";
String line = STR.process(tmpl);

The important point about the process() method is that it can make sure that the interpolation is done in a safe way — avoiding any kinds of injection attacks as well as customizing it in clever ways.

For example, here’s an example where we create a processor to directly return the JSON object from the string without going through an extra step of conversion.

/* Define the Template Processor */
class JsonTemplateProcessor implements
StringTemplate.Processor<JSONObject,Throwable> {

@Override
public JSONObject process(StringTemplate tmpl)
throws Throwable {

String jsonStr = tmpl.interpolate();
return new JSONObject(jsonStr);
}
}

/* Use the Template Processor */
var JST = new JsonTemplateProcessor();
JSONObject jsonObj = JST."""
{
name : "\{name}",
age : \{age}
}
""";

System.out.println(jsonObj.get("name"));

We can also use the functional style as follows by using the of() method in the Processor.

// Create a JST Template Processor using Lambda
var JST = StringTemplate.Processor.of(tmpl -> {
String jsonStr = tmpl.interpolate();
return new JSONObject(jsonStr);
});

// Use the Template Processor
JSONObject jsonObj = JST."""
{
name : "\{name}",
age : \{age}
}
""";

System.out.println(jsonObj.get("name"));

Because Processor is a Functional interface, we can also create it by directly assigning a lambda to it.

// Create a Processor by directly assigning the Lambda
StringTemplate.Processor<JSONObject,Exception> JST = t -> {
String jsonStr = t.interpolate();
return new JSONObject(jsonStr);
};

One interesting use of String Templates is to not return anything but simply log the message to standard out.

// Notice that this Processor returns null
var PRT = StringTemplate.Processor.of(t -> {
String str = t.interpolate();
System.out.println(str);
return null;
});

// Use PRT to log message
PRT."My name is \{name}. My age is \{age}.";

Template Processor and Security

One of most important goals of String Templates is that — composing the Java Strings need to be secure. That’s the reason why just String Interpolation was not satisfactory to the Java Engineers. By using a processor in the middle, developers have the option to validate the values and expressions that are passed to the template for sanity.

Here’s an example (incomplete) which shows a SQL Template Processor to make sure that the values passed to the SQL Template string are sanitized — to avoid SQL injection attacks.

class SQLTemplateProcessor implements 
StringTemplate.Processor<String, Throwable> {

@Override
public String process(StringTemplate tmpl) throws Throwable {

// Get the fragments and values
List<String> fragments = tmpl.fragments();
List<Object> values = tmpl.values();

// sanitize the data
values = sanitize(values);
return StringTemplate.interpolate(fragments, values);
}

private List<Object> sanitize(List<Object> values) {

// Code to sanitize values not included
// Any string with Quote can be escaped here
// values = ...

return values;
}

}

This should give you a good idea about Java String Templates and Template Expressions.

Feel free to comment and clap on the article.

Visit my YouTube channel page at https://www.youtube.com/@viraj_shetty for some great Java programming and OAuth videos

I also have a discounted course (12.99$ or best local price) on Udemy called Java Virtual Threads and Structured Concurrency which takes a comprehensive look at Virtual Threads, Structured Concurrency, Scoped Values and their integration with Spring Boot

Summary

In summary, String Templates provide us with several benefits including

  • Making it easy to express strings that include values computed at run time
  • Enabling the creation of non-string values computed from literal text
  • Improving the security of Java programs that compose strings from user-provided values

--

--