Please, Java. Do Finally Support Multiline String Literals

I understand the idea of Java-the-language being rather hard to maintain in a backwards-compatible way. I understand the idea of JDK API, such as the collections, to be rather tough not to break. Yes.

I don’t understand why Java still doesn’t have multiline string literals.

How often do you write JDBC code (or whatever other external language or markup, say, JSON or XML you want to embed in Java) like this?

try (PreparedStatement s = connection.prepareStatement(
    "SELECT * "
  + "FROM my_table "
  + "WHERE a = b "
)) {
    ...
}

What’s the issue?

  • Syntax correctness, i.e. don’t forget to add a whitespace at the end of each line
  • Style in host language vs style in external language, sure the above code looks “nicely” formatted in Java, but it’s not formatted for the consuming server side
  • SQL injection, didn’t we teach our juniors not to perform this kind of string concatenation in SQL, to prevent SQL injection? Sure, the above is still safe, but what keeps a less experienced maintainer from embedding, accidentally, user input?

Today, I was working with some code written in Xtend, a very interesting language that compiles into Java source code. Xtend is exceptionally useful for templating (e.g. for generating jOOQ’s Record1Record22 API). I noticed another very nice feature of multi line strings:

The lack of need for escaping!

Multi line strings in Xtend are terminated by triple-apostrophes. E.g.

// Xtend
val regex = '''import java\.lang\.AutoCloseable;'''

Yes, the above is a valid Java regular expression. I’m escaping the dots when matching imports of the AutoCloseable type. I don’t have to do this tedious double-escaping that I have to do in ordinary strings to tell the Java compiler that the backslash is really a backslash, not Java escaping of the following character:

// Java
String regex = "import java\\.lang\\.AutoCloseable;";

So… Translated to our original SQL example, I would really like to write this, instead:

try (PreparedStatement s = connection.prepareStatement(
    '''SELECT *
       FROM my_table
       WHERE a = b'''
)) {
    ...
}

With a big nice-to-have plus: String interpolation (even PHP has it)!

String tableName = "my_table";
int b = 1;
try (PreparedStatement s = connection.prepareStatement(
    '''SELECT *
       FROM ${tableName}
       WHERE a = ${b}'''
)) {
    ...
}

Small but very effective improvement

This would be a very small (in terms of language complexity budget: Just one new token) but very effective improvement for all of us out there who are embedding an external language (SQL, XML, XPath, Regex, you name it) in Java. We do that a lot. And we hate it.

It doesn’t have to be as powerful as Xtend’s multiline string literals (which really rock with their whitespace management for formatting, and templating expressions). But it would be a start.

Please, make this a New Year’s resolution! :)

MySQL Bad Idea #573

This is MySQL’s Bad Idea #573 (after #384, which I’ve blogged about before) I’ve just had a terrible experience with a bug report from the jOOQ User Group, related to escaping of backslashes in string literals in MySQL. First, I thought to myself, whatever. SQL doesn’t escape backslashes. The only escape character within a string literal according to the early SQL standards is the quote as in quote quote. Citing from SQL-1992 (slightly simplified):

<character string literal> ::=
    <quote> [ <character representation>... ] <quote>

<character representation> ::=
    <nonquote character>
  | <quote symbol><nonquote character> ::= !! See the Syntax Rules.
<quote symbol> ::= <quote><quote>

Alright? Crystal clear. There’s no escaping other than <quote><quote>

The only time when you will need to be able to escape something is with the LIKE predicate, in case you want to escape % and _ symbols. You can then use the ESCAPE clause:

<like predicate> ::=
    <match value> [ NOT ] LIKE <pattern>
    [ ESCAPE <escape character> ]

I have now learned, that MySQL (and of course MariaDB) unlike any other database also support quoting with backslashes, similar to Java and other languages. That’s not a problem per se, although from a cross-vendor compatibility perspective, it’s quite nasty. But then, I’ve discovered there is a flag called NO_BACKSLASH_ESCAPES:

This just reminds me of PHP’s horrible magic quotes. In fact, combine arbitrary configurations of PHP and MySQL on your server and good luck to you of ever getting string literals right. Sigh.