I added a commit on my branch that is more liberal, applying abs() and % regardless of which approach (class, expression, or default) is used... therefore requiring no asserts and allowing users to  decide whether they just want to "hash" or if they want to get down to the individual partition index. After all, the abs() and % operations have no effect for any value within the range, e.g. if partitionCount is N then any value X within the range of 0 to N-1 will not be modified by either abs(X) or X % N.

Regarding the comment about adding #partitionCount as a variable in the EvaluationContext. We *could* do that only in the case where the String value of the expression does contain #partitionCount (otherwise, it's not being used so would be unnecessary). That would mean we only create a new EvaluationContext instance for the cases where that value is expected for the expression evaluation. However, it's probably not worth pursuing since - as you mentioned - this is critical path code, and the option of providing a class is going to be a better option if someone really needs that level. Otherwise for SpEL it would be ok to "hardcode" given that the count is already known, e.g.:

````
stream create s --definition "foo | bar"

stream deploy s --properties="module.foo.producer.partitionKeyExpression=payload.customerId,module.foo.producer.partitionSelectorExpression=someHash(#root)%5,module.bar.count=5"
````