Skip to content

String Templating

Ben Yu edited this page Oct 27, 2024 · 9 revisions

String Formatting

For the most common use case, you can define a string format to be reused througout a class:

private static final StringFormat BUCKET_RESOURCE_NAME =
    new StringFormat("projects/{project}/locations/{location}/buckets/{bucket}");

...
// 200 lines away
String bucketResourceName = BUCKET_RESOURCE_NAME.format(projectId, location, bucket);

Or a public format with placeholders to be shared across files:

public final class ResourceNameFormats {
  public static final String BUCKET_FORMAT =
      "projects/{project}/locations/{location}/buckets/{bucket}";
}


// Another package, another file
String bucketResourceName =
    StringFormat.using(ResourceNameFormats.BUCKET_FORMAT, projectId, location, bucket);

In both cases, it's strongly recommended to use the mug-errorprone compile-time plugin alongside ErrorProne with its rich set of compile-time checks to protect yourself from mistakenly passing the arguments in the wrong order (or passing the wrong thing).

For example the compile-time check will make sure that you pass projectId or project.id() or foo.getProject() for the {project} placeholder. If you instead passed pageId in the place of project, or passed the 3 placeholder values in the wrong order, you'll get a compilation error.

String "Templating"

StringFormat also supports templating into non-String types, as inspired by JEP 459. It allows extensions to be built with custom interpolation rules to create arbitrary types off of a string template.

For example the SafeQuery class is a SQL templating engine built on top of StringFormat. It guards against SQL injection; and at the same time the ErrorProne compile-time checks for correct argument ordering works for all extensions including SafeQuery:

SafeQuery.of("select {columns} from tbl where id = '{id}'", columns, userId)

Will Java String Template in Java 24 (or future versions) supersede it?

JEP 459 and following revisions will add string templating to the language sooner or later.

The syntax will likely look like "Hello \{audience}, today is \{day}." There may be slight variants to the placeholder whether it's \{placeholder}, or ${placeholder} or perhaps there is a prefix ahead of the double quote. And there may be a "processor", or not. Hard to say.

But one thing is certain: we'll be able to interpolate variables into strings.

That begs the question: if official templating is so close, is StringFormat.Template still needed?

It looks like the main benefit of StringFormat template won't be provided by the JEP. That is: to be able to reuse a template with compile-time protection against incorrect placeholder order.

With the JEP, you can't define a bunch of templates (like official user agent patterns, important user-facing messages) and reuse them in different places. The placeholders must be variables in scope. You could wrap them in methods with parameters. But then you risk the parameters being passed in the wrong order. If the template has many placeholders, it becomes the method with many parameters anti-pattern.

Named parameters, if ever added to the language, when combined with the StringTemplate JEP should supersede StringFormat.