Java war lange die Sprache, in der man für formatierte Strings String.format() oder umständliche +-Ketten schreiben musste. Mit Java 21 (JEP 430) kam endlich eine elegante Lösung: String Templates. Dieser Artikel zeigt die Syntax, erklärt eigene Template-Prozessoren und demonstriert, wie String Templates SQL-Injection-Angriffe zur Compile-Time verhindern.
Wichtig vorab: String Templates sind in Java 21 (JEP 430) und 22 (JEP 459) ein Preview-Feature. Die für JDK 23 geplante Finalisierung (JEP 465) wurde zurückgezogen (Status: Withdrawn). Das Feature ist daher ab JDK 23 nicht mehr verfügbar und befindet sich im Redesign. Mit JDK 21/22 und --enable-preview ist es weiterhin nutzbar.
Grundlagen: STR und FMT
Die Basis-Syntax ist PROZESSOR."Text \{ausdruck}" — der Template-Prozessor STR ersetzt \{...} mit dem Ergebnis des Ausdrucks:
String name = "Lena";
int bestellungen = 42;
String nachricht = STR."Hallo \{name}, du hast \{bestellungen} Bestellungen.";
<em>// "Hallo Lena, du hast 42 Bestellungen."</em>
<em>// Ausdrücke sind vollständig: Methodenaufrufe, Arithmetik, sogar andere Templates</em>
String info = STR."Summe: \{bestellungen * 2 + 10}";
<em>// "Summe: 94"</em>
Code-Sprache: JavaScript (javascript)
Der FMT-Prozessor kombiniert Templates mit java.util.Formatter-Spezifikationen:
record Produkt(String name, double preis) {}
Produkt[] produkte = {
new Produkt("Tastatur", 89.99),
new Produkt("Monitor", 349.00),
new Produkt("Maus", 24.50)
};
String tabelle = FMT."""
%-15s\{produkte[0].name} %8.2f\{produkte[0].preis}
%-15s\{produkte[1].name} %8.2f\{produkte[1].preis}
%-15s\{produkte[2].name} %8.2f\{produkte[2].preis}
""";
<em>// Tastatur 89.99</em>
<em>// Monitor 349.00</em>
<em>// Maus 24.50</em>
Code-Sprache: PHP (php)
Text Blocks (""") und Templates ergänzen sich perfekt für mehrzeilige Strings:
String json = STR."""
{
"name": "\{name}",
"bestellungen": \{bestellungen}
}
""";
Code-Sprache: PHP (php)
RAW: Zugriff auf unverarbeitete Templates
Der RAW-Prozessor liefert ein StringTemplate-Objekt zurück:
int x = 10, y = 20;
StringTemplate st = RAW."\{x} plus \{y} gleich \{x + y}";
st.fragments(); <em>// ["", " plus ", " gleich ", ""]</em>
st.values(); <em>// [10, 20, 30]</em>
Code-Sprache: JavaScript (javascript)
Wichtig: RAW produziert absichtlich keinen String — du musst das Template immer explizit durch einen Prozessor schicken, bevor ein String entsteht. Das verhindert versehentliche, ungeprüfte Interpolation.
SQL-Injection mit String Templates verhindern
Dieses Beispiel zeigt, warum String Templates für Datenbankzugriffe so wertvoll sind. Angenommen, ein Angreifer gibt diesen Suchtext ein:
String suchbegriff = "Müller' OR 1=1 --";
<em>// Gefährliche String-Konkatenation:</em>
String unsafe = "SELECT * FROM kunden WHERE name = '" + suchbegriff + "'";
<em>// Ergebnis: SELECT * FROM kunden WHERE name = 'Müller' OR 1=1 --'</em>
<em>// -> Gibt ALLE Datensätze zurück!</em>
Code-Sprache: JavaScript (javascript)
Ein eigener Template-Prozessor ersetzt \{...}-Stellen mit JDBC-?-Platzhaltern und übergibt die Werte sicher via PreparedStatement:
import java.sql.*;
record QueryProcessor(Connection conn)
implements StringTemplate.Processor<PreparedStatement, SQLException> {
public PreparedStatement process(StringTemplate st) throws SQLException {
String query = String.join("?", st.fragments());
PreparedStatement ps = conn.prepareStatement(query);
int index = 1;
for (Object value : st.values()) {
switch (value) {
case Integer i -> ps.setInt(index++, i);
case Long l -> ps.setLong(index++, l);
case Double d -> ps.setDouble(index++, d);
case Boolean b -> ps.setBoolean(index++, b);
case null -> ps.setNull(index++, Types.NULL);
default -> ps.setString(index++, value.toString());
}
}
return ps;
}
}
<em>// Verwendung:</em>
var DB = new QueryProcessor(connection);
PreparedStatement stmt = DB."""
SELECT * FROM kunden WHERE name = \{suchbegriff}
""";
ResultSet rs = stmt.executeQuery();
Code-Sprache: PHP (php)
Selbst mit bösartigem Input — Müller' OR 1=1 -- — entsteht daraus:
SELECT * FROM kunden WHERE name = ?
mit suchbegriff als gebundenem Parameter. Keine SQL-Injection möglich.
Eigener Template-Prozessor
Das Interface ist einfach: StringTemplate.Processor<R, E>. R ist der Rückgabetyp, E die mögliche Exception. Hier ein Prozessor, der JSON produziert und gleichzeitig auf Injection prüft:
StringTemplate.Processor<String, IllegalArgumentException> JSON =
st -> {
String quote = "\"";
for (Object value : st.values()) {
if (value instanceof String s && s.contains(quote)) {
throw new IllegalArgumentException(
"String-Wert enthält Anführungszeichen: " + s);
}
}
List<Object> safeValues = new ArrayList<>();
for (Object v : st.values()) {
if (v instanceof String s) {
safeValues.add(quote + s + quote);
} else {
safeValues.add(v);
}
}
return StringTemplate.interpolate(st.fragments(), safeValues);
};
<em>// Nutzung:</em>
String person = "Lena";
int alter = 30;
String result = JSON."""
{"name": \{person}, "alter": \{alter}}
""";
<em>// {"name": "Lena", "alter": 30}</em>
Code-Sprache: PHP (php)
Preview-Feature aktivieren
Für Java 21 oder 22 mit --enable-preview:
javac --enable-preview --release 21 MeinProgramm.java
java --enable-preview MeinProgramm
Code-Sprache: CSS (css)
In Maven:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerArgs>
<arg>--enable-preview</arg>
</compilerArgs>
</configuration>
</plugin>
Code-Sprache: HTML, XML (xml)
Ausblick
Die für JDK 23 geplante Finalisierung der String Templates (JEP 465) wurde zurückgezogen (Status: Withdrawn). Die enge Kopplung von Template-Erfassung und -Verarbeitung in der Syntax PROZESSOR."template" galt als problematisch. Stand Juli 2026 gibt es noch keinen Nachfolge-JEP; ein Redesign mit möglicherweise getrennten Schritten für Capture und Processing wird in der Community diskutiert. In der Zwischenzeit bleibt JDK 21/22 die einzige Möglichkeit, mit dieser Preview zu experimentieren.
Die grundlegende Idee — typsichere, validierbare String-Interpolation mit anwendungsspezifischen Prozessoren — bleibt relevant, auch wenn das finale Design noch offen ist.