19. White space and quote rules

It is only necessary to quote parameter values if they contain spaces or the | character. Here the transform processor is being passed a SpEL expression that will be applied to any data it encounters:

transform --expression='new StringBuilder(payload).reverse()'

If the parameter value needs to embed a single quote, use two single quotes:

// Query is: Select * from /Customers where name='Smith'
scan --query='Select * from /Customers where name=''Smith'''

19.1 Quotes and Escaping

There is a Spring Shell based client that talks to the Data Flow Server that is responsible for parsing the DSL. In turn, applications may have applications properties that rely on embedded languages, such as the Spring Expression Language.

The shell, Data Flow DSL parser, and SpEL have rules about how they handle quotes and how syntax escaping works. When combined together, confusion may arise. This section explains the rules that apply and provides examples of the most complicated situations you will encounter when all three components are involved.

[Note]It’s not always that complicated

If you don’t use the Data Flow shell, for example you’re using the REST API directly, or if applications properties are not SpEL expressions, then escaping rules are simpler.

19.1.1 Shell rules

Arguably, the most complex component when it comes to quotes is the shell. The rules can be laid out quite simply, though:

  • a shell command is made of keys (--foo) and corresponding values. There is a special, key-less mapping though, see below
  • a value can not normally contain spaces, as space is the default delimiter for commands
  • spaces can be added though, by surrounding the value with quotes (either single ['] or double ["] quotes)
  • if surrounded with quotes, a value can embed a literal quote of the same kind by prefixing it with a backslash (\)
  • Other escapes are available, such as \t, \n, \r, \f and unicode escapes of the form \uxxxx
  • Lastly, the key-less mapping is handled in a special way in the sense that if does not need quoting to contain spaces

For example, the shell supports the ! command to execute native shell commands. The ! accepts a single, key-less argument. This is why the following works:

dataflow:>! rm foo

The argument here is the whole rm foo string, which is passed as is to the underlying shell.

As another example, the following commands are strictly equivalent, and the argument value is foo (without the quotes):

dataflow:>stream destroy foo
dataflow:>stream destroy --name foo
dataflow:>stream destroy "foo"
dataflow:>stream destroy --name "foo"

19.1.2 DSL parsing rules

At the parser level (that is, inside the body of a stream or task definition) the rules are the following:

  • option values are normally parsed until the first space character
  • they can be made of literal strings though, surrounded by single or double quotes
  • To embed such a quote, use two consecutive quotes of the desired kind

As such, the values of the --expression option to the filter application are semantically equivalent in the following examples:

filter --expression=payload>5
filter --expression="payload>5"
filter --expression='payload>5'
filter --expression='payload > 5'

Arguably, the last one is more readable. It is made possible thanks to the surrounding quotes. The actual expression is payload > 5 (without quotes).

Now, let’s imagine we want to test against string messages. If we’d like to compare the payload to the SpEL literal string, "foo", this is how we could do:

filter --expression=payload=='foo'           1
filter --expression='payload == ''foo'''     2
filter --expression='payload == "foo"'       3

1

This works because there are no spaces. Not very legible though

2

This uses single quotes to protect the whole argument, hence actual single quotes need to be doubled

3

But SpEL recognizes String literals with either single or double quotes, so this last method is arguably the best

Please note that the examples above are to be considered outside of the shell, for example if when calling the REST API directly. When entered inside the shell, chances are that the whole stream definition will itself be inside double quotes, which would need escaping. The whole example then becomes:

dataflow:>stream create foo --definition "http | filter --expression=payload='foo' | log"
dataflow:>stream create foo --definition "http | filter --expression='payload == ''foo''' | log"
dataflow:>stream create foo --definition "http | filter --expression='payload == \"foo\"' | log"

19.1.3 SpEL syntax and SpEL literals

The last piece of the puzzle is about SpEL expressions. Many applications accept options that are to be interpreted as SpEL expressions, and as seen above, String literals are handled in a special way there too. The rules are:

  • literals can be enclosed in either single or double quotes
  • quotes need to be doubled to embed a literal quote. Single quotes inside double quotes need no special treatment, and vice versa

As a last example, assume you want to use the transform processor. This processor accepts an expression option which is a SpEL expression. It is to be evaluated against the incoming message, with a default of payload (which forwards the message payload untouched).

It is important to understand that the following are equivalent:

transform --expression=payload
transform --expression='payload'

but very different from the following:

transform --expression="'payload'"
transform --expression='''payload'''

and other variations.

The first series will simply evaluate to the message payload, while the latter examples will evaluate to the actual literal string payload (again, without quotes).

19.1.4 Putting it all together

As a last, complete example, let’s review how one could force the transformation of all messages to the string literal hello world, by creating a stream in the context of the Data Flow shell:

dataflow:>stream create foo --definition "http | transform --expression='''hello world''' | log" 1
dataflow:>stream create foo --definition "http | transform --expression='\"hello world\"' | log" 2
dataflow:>stream create foo --definition "http | transform --expression=\"'hello world'\" | log" 3

1

This uses single quotes around the string (at the Data Flow parser level), but they need to be doubled because we’re inside a string literal (very first single quote after the equals sign)

2 3

use single and double quotes respectively to encompass the whole string at the Data Flow parser level. Hence, the other kind of quote can be used inside the string. The whole thing is inside the --definition argument to the shell though, which uses double quotes. So double quotes are escaped (at the shell level)