Thursday, December 21, 2023

Java String Template

The first time you look at a Java String Template, it feels right and wrong simultaneously. 

String first = "John";
String last = "Smith";
String info = STR. "My first name is \{ first } and my last name is \{ last }" ;       

Right because the result of the final statement is with the placeholders correctly evaluated and filled in. It feels wrong because of the strange new "STR." expression and the way the placeholders are escaped "\{ }" 

However now that I have looked at it for some time, the reasoning does make sense and I have gotten used to the new syntax.

So let’s start with the motivation first, I will mostly follow the structure of the well-explained JEP that goes with this feature.


Motivation

It has traditionally been cumbersome to compose a string using data and expressions, taking an example from the JEP, say to compose:

10 plus 20 equals 30

would look something like this:
int x = 10;
int y = 20;
String s = new StringBuilder()
        .append(x)
        .append(" plus ")
        .append(y)
        .append(" equals ")
        .append(x + y)
        .toString();
With String Template such extensive composing is no longer needed and looks something like this:

int x = 10;
int y = 20;
String s = STR. "\{ x } plus \{ y } equals \{ x + y }" ;


Workings

So there are a few parts to it:
  1. the String template \{ x } plus \{ y } equals \{ x + y }, which is intuitive, the placeholder variables and expressions in a String template are escaped using \{ } syntax
  2. brand new expression syntax, STR.<string template>
  3. STR is the “Template Processor”, that returns the final processed string
It is illegal to have a String template without a String Template Processor, if I were to try without having it, the following is the error I get in Intellij:


String Template Processor

String Template Processor is the part that provides special powers, imagine processors that can avoid SQL injection while crafting a SQL statement!

Looking closely first at a raw String Template, itis obtained by using a RAW String Template Processor

String first = "John";
String last = "Smith";
StringTemplate st = RAW. "My first name is \{ first } and my last name is \{ last }" ;


And is composed of two sets of data:

  • fragments, which is [“My first name is” , “and my last name is” , “”] in the template above, the pieces of fixed text around the template placeholders
  • values — which are the resolved placeholders, so in my example they are [“John”, “Smith”]

A Template Processor simply uses the “fragments” and “values” to put the final output together, for eg, I can implement a custom Template Processor that capitalizes the fragments the following way:

StringTemplate.Processor<String, RuntimeException> UPPER =
        StringTemplate.Processor.of((StringTemplate st) -> {
            StringBuilder sb = new StringBuilder();
            Iterator<String> fragIter = st.fragments().iterator();
            for (Object value : st.values()) {
            sb.append(fragIter.next().toUpperCase());
            sb.append(value);
            }
            sb.append(fragIter.next());
            return sb.toString();
        });
You can imagine highly specialized String Template Processors coming up that can handle the scenario of SQL injection attacks for example.

Conclusion

String Template is a welcome addition to the Java ecosystem and simplifies scenarios where a string needs to be composed of various expressions. It is still a preview feature as of Java 21, so its use in production code is not recommended until it is GA, but it is worth checking out to see how it works.

These are the resources that go with this article:

String Template JEP — https://openjdk.org/jeps/430