DEV Community

9mac-dev
9mac-dev

Posted on

Java 17 Features Every Senior Developer Should Know - Part 5: Text Blocks

Part 5 of 6 | For senior Java developers modernizing codebases to Java 17

The Problem Text Blocks Solve

Before Java 15, embedding multi-line strings in Java code was a nightmare of escape sequences, concatenation operators, and unreadable structure. Every JSON fixture, SQL query, or HTML template required extensive reformatting:

// The old way - escape sequence hell
String json = "{\n" +
              "  \"name\": \"Alice\",\n" +
              "  \"age\": 30,\n" +
              "  \"email\": \"alice@example.com\"\n" +
              "}";

String query = "SELECT u.name, u.email, o.total\n" +
               "FROM users u\n" +
               "JOIN orders o ON u.id = o.user_id\n" +
               "WHERE o.status = 'COMPLETED'\n" +
               "ORDER BY o.created_at DESC";
Enter fullscreen mode Exit fullscreen mode

Text blocks eliminate this pain entirely while introducing critical security considerations that every senior developer must understand.

Why This Matters

Readability Crisis: Traditional multi-line strings obscure the actual data structure with Java syntax noise (+, \n, \"), making maintenance difficult and copy-pasting from external tools (Postman, SQL clients) a reformatting burden.

Security Landmines: Text blocks combined with formatted() create powerful template capabilities, but misuse with SQL queries or HTML content introduces SQL injection and XSS vulnerabilities that can compromise production systems.

Maintenance Burden: Every content update requires modifying multiple lines with careful attention to escape sequences and concatenation operators—a recipe for bugs.

What Are Text Blocks?

Text blocks use triple-double-quote delimiters (""") to create multi-line string literals that automatically normalize line terminators, strip common indentation, and eliminate most escape sequences:

// The new way - clean and readable
String json = """
    {
      "name": "Alice",
      "age": 30,
      "email": "alice@example.com"
    }
    """;

String query = """
    SELECT u.name, u.email, o.total
    FROM users u
    JOIN orders o ON u.id = o.user_id
    WHERE o.status = 'COMPLETED'
    ORDER BY o.created_at DESC
    """;
Enter fullscreen mode Exit fullscreen mode

Key benefits:

  • No escape sequences for quotes or newlines
  • Natural indentation preserved
  • Copy-paste friendly from external tools
  • Zero runtime performance overhead

When to Use Text Blocks

Perfect for:

  • JSON, XML, HTML structures in test fixtures
  • SQL queries (especially complex CTEs)
  • Email templates and invoices
  • Configuration files and API responses
  • Any multi-line literal in embedded languages

Avoid for:

  • Single-line strings (use regular "...")
  • Platform-specific line endings (text blocks normalize to \n)
  • Strings requiring immediate complex processing

Real-World Examples

Example 1: JSON Test Fixtures

public static String getUserJSONFormatted(String name, int age, String email) {
    return """
        {
          "name": "%s",
          "age": %d,
          "email": "%s"
        }""".formatted(name, age, email);
}

// Usage
String json = getUserJSONFormatted("Charlie", 25, "charlie@example.com");
Enter fullscreen mode Exit fullscreen mode

Output:

{
  "name": "Charlie",
  "age": 25,
  "email": "charlie@example.com"
}
Enter fullscreen mode Exit fullscreen mode

Example 2: HTML Templates Without Escape Hell

public static String getDashboardHTML() {
    return """
        <html>
          <head>
            <title>User Dashboard</title>
          </head>
          <body>
            <h1>Welcome, User!</h1>
            <p>This is your dashboard.</p>
          </body>
        </html>""";
}
Enter fullscreen mode Exit fullscreen mode

No more escaping quotes! The structure is immediately clear, matching exactly what you'd see in design tools.

Example 3: Email Template System

public static String renderEmailTemplate(String recipientName, String activationUrl, String expirationHours) {
    return """
        <html>
          <body style="font-family: Arial, sans-serif;">
            <h2>Welcome, %s!</h2>
            <p>Thank you for signing up. Please activate your account within %s hours.</p>
            <p><a href="%s" style="background-color: #007bff; color: white; padding: 10px 20px;">Activate Account</a></p>
            <p>Best regards,<br>The Team</p>
          </body>
        </html>""".formatted(recipientName, expirationHours, activationUrl);
}
Enter fullscreen mode Exit fullscreen mode

Text blocks combined with formatted() create lightweight template systems without external dependencies—perfect for emails, invoices, and configurations.

Example 4: Complex SQL with CTEs

public static String getTopCustomersQuerySafe() {
    return """
        WITH customer_totals AS (
            SELECT u.id, u.name, u.email,
                   SUM(o.total) as total_spent,
                   COUNT(o.order_id) as order_count
            FROM users u
            JOIN orders o ON u.id = o.user_id
            WHERE o.status = ?
              AND o.created_at >= ?
            GROUP BY u.id, u.name, u.email
        )
        SELECT id, name, email, total_spent, order_count
        FROM customer_totals
        WHERE total_spent >= ?
        ORDER BY total_spent DESC
        LIMIT ?""";
}
Enter fullscreen mode Exit fullscreen mode

Notice the ? placeholders—this demonstrates the secure pattern for SQL with text blocks.

Security Considerations (CRITICAL)

SQL Injection - The Danger Zone

NEVER use formatted() with SQL queries and user input:

// ❌ DANGEROUS - SQL Injection Vulnerability!
String status = userInput;  // User enters: "COMPLETED' OR '1'='1"
String sql = """
    SELECT * FROM orders
    WHERE status = '%s'
    """.formatted(status);
// Resulting SQL: SELECT * FROM orders WHERE status = 'COMPLETED' OR '1'='1'
// This returns ALL orders, bypassing security!
Enter fullscreen mode Exit fullscreen mode

Worse attacks can delete entire tables:

// ❌ If user enters: "'; DROP TABLE orders; --"
String sql = """
    SELECT * FROM orders WHERE status = '%s'
    """.formatted(maliciousInput);
// Your entire orders table is DELETED!
Enter fullscreen mode Exit fullscreen mode

The Safe SQL Pattern

Always use PreparedStatement with text blocks:

// ✅ SAFE - PreparedStatement prevents SQL injection
String query = """
    SELECT * FROM orders
    WHERE status = ?
      AND total >= ?
    """;

try (PreparedStatement ps = connection.prepareStatement(query)) {
    ps.setString(1, userInput);  // Automatically escaped - safe!
    ps.setDouble(2, minAmount);
    try (ResultSet rs = ps.executeQuery()) {
        // Process results
    }
}
Enter fullscreen mode Exit fullscreen mode

Key points:

  • Text blocks improve SQL readability
  • PreparedStatement prevents injection
  • Use ? placeholders, NOT %s formatting
  • Set parameters via setString(), setInt(), setDouble(), etc.

XSS Injection - HTML Security

NEVER use formatted() with HTML and user input without escaping:

// ❌ DANGEROUS - XSS Vulnerability
String username = userInput;  // User enters: "<script>alert('XSS')</script>"
String html = """
    <html>
      <body>
        <h1>Welcome, %s!</h1>
      </body>
    </html>""".formatted(username);
// The script executes in the browser, potentially stealing cookies!
Enter fullscreen mode Exit fullscreen mode

Always escape HTML entities:

// ✅ SAFE - Escape HTML before formatting
public static String escapeHtml(String input) {
    return input
        .replace("&", "&amp;")
        .replace("<", "&lt;")
        .replace(">", "&gt;")
        .replace("\"", "&quot;")
        .replace("'", "&#x27;");
}

String username = escapeHtml(userInput);
String html = """
    <html>
      <body>
        <h1>Welcome, %s!</h1>
      </body>
    </html>""".formatted(username);
Enter fullscreen mode Exit fullscreen mode

Advanced Patterns

Indentation Rules

The closing """ delimiter determines indentation stripping:

// Closing delimiter indented - strips that amount
String indented = """
    Hello
    World
    """;
// Content: "Hello\nWorld\n" (4 spaces stripped from each line)

// Closing delimiter aligned left - minimal stripping
String leftAligned = """
    Hello
    World
""";
// Content: "    Hello\n    World\n" (preserves indentation)
Enter fullscreen mode Exit fullscreen mode

Essential Space and Line Continuation

Two new escape sequences provide fine-grained control:

// \s preserves trailing whitespace
String essential = """
    Line with trailing space:\s
    Another line
    """;

// \ continues lines without newline
String continued = """
    This is a very long sentence that we want to \
    split in source code but keep as \
    one line in the string.
    """;
Enter fullscreen mode Exit fullscreen mode

Relative Indentation Preserved

String structured = """
    Level 1
        Level 2
            Level 3
        Level 2
    Level 1
    """;
Enter fullscreen mode Exit fullscreen mode

Text blocks preserve relative indentation while stripping common leading whitespace—perfect for code examples and structured data.

Key Insight

Text blocks eliminate the impedance mismatch between Java code and embedded languages (JSON, SQL, HTML), making maintenance dramatically easier. However, they are a readability feature, NOT a security feature—always use PreparedStatement for SQL and escape HTML entities for web content.

Read the Full Article

The complete guide includes:

  • 8 comprehensive examples with full code and detailed output
  • Security deep-dive covering SQL injection and XSS prevention patterns
  • Indentation edge cases and sophisticated formatting rules
  • Template system patterns for emails, invoices, and configurations
  • Performance analysis demonstrating zero runtime overhead
  • Text blocks vs template engines decision framework
  • Complete implementation checklist for migrating existing code
  • Common mistakes and how to avoid them

Read more: https://blog.9mac.dev/java-17-features-every-senior-developer-should-know-part-5-text-blocks


Clone the repository and run examples:

git clone https://github.com/dawid-swist/blog-9mac-dev-code.git
cd blog-post-examples/java/2025-10-25-java17-features-every-senior-developer-should-know
../../gradlew test --tests *part5*
Enter fullscreen mode Exit fullscreen mode

All 8 examples include complete test coverage demonstrating secure and unsafe patterns.


Series Navigation:

Top comments (0)