Skip to content

Commit 7272bb0

Browse files
[NU-2106] Fix spel template evaluation in runtime (#7764)
1 parent 96ebf2d commit 7272bb0

File tree

4 files changed

+39
-5
lines changed

4 files changed

+39
-5
lines changed

components-api/src/main/scala/pl/touk/nussknacker/engine/api/TemplateEvaluationResult.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ case class TemplateEvaluationResult(renderedParts: List[TemplateRenderedPart]) {
55
}
66

77
sealed trait TemplateRenderedPart {
8-
def value: String
8+
def value: AnyRef
99
}
1010

1111
object TemplateRenderedPart {
1212
case class RenderedLiteral(value: String) extends TemplateRenderedPart
1313

14-
case class RenderedSubExpression(value: String) extends TemplateRenderedPart
14+
case class RenderedSubExpression(value: AnyRef) extends TemplateRenderedPart
1515
}

docs/Changelog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@
131131
static values.
132132
* JsonDefaultExpression and AvroDefaultExpression default string values changed to SpEL template.
133133
* For now on, default values are provided for dry run parameters.
134+
* [#7764](https://github.com/TouK/nussknacker/pull/7764) Fix SpEL template evaluation on runtime. For now on, there is
135+
no need to pass .toString on variable in SpEL template expression.
134136

135137
## 1.18
136138

scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/spel/SpelExpression.scala

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,7 @@ class SpelExpression(
142142
def renderExpression(expression: Expression): List[TemplateRenderedPart] = expression match {
143143
case literal: LiteralExpression => List(RenderedLiteral(literal.getExpressionString))
144144
case spelExpr: org.springframework.expression.spel.standard.SpelExpression =>
145-
// TODO: Should we use the same trick with re-parsing after ClassCastException as we use in ParsedSpelExpression?
146-
List(RenderedSubExpression(spelExpr.getValue[String](evaluationContext, classOf[String])))
145+
List(RenderedSubExpression(spelExpr.getValue(evaluationContext)))
147146
case composite: CompositeStringExpression => composite.getExpressions.toList.flatMap(renderExpression)
148147
case other =>
149148
throw new IllegalArgumentException(
@@ -310,7 +309,7 @@ object SpelExpressionParser extends LazyLogging {
310309
classDefinitionSet: ClassDefinitionSet,
311310
): SpelExpressionParser = {
312311

313-
val parser = new org.springframework.expression.spel.standard.SpelExpressionParser(
312+
val parser = new AdjustingTemplateExpressionSpringSpelExpressionParser(
314313
// we have to pass classloader, because default contextClassLoader can be sth different than we expect...
315314
new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, classLoader)
316315
)
@@ -328,4 +327,24 @@ object SpelExpressionParser extends LazyLogging {
328327
)
329328
}
330329

330+
private class AdjustingTemplateExpressionSpringSpelExpressionParser(configuration: SpelParserConfiguration)
331+
extends org.springframework.expression.spel.standard.SpelExpressionParser(configuration) {
332+
333+
// Override for: org.springframework.expression.common.TemplateAwareExpressionParser.parseTemplate, because
334+
// the spring should return only the StringExpression for a template
335+
override def parseExpression(expressionString: String, context: ParserContext): Expression = {
336+
val expression = super.parseExpression(expressionString, context)
337+
if (context != null && context.isTemplate) {
338+
expression match {
339+
case l: LiteralExpression => l
340+
case s: CompositeStringExpression => s
341+
case other => new CompositeStringExpression(expressionString, Array(other))
342+
}
343+
} else {
344+
expression
345+
}
346+
}
347+
348+
}
349+
331350
}

scenario-compiler/src/test/scala/pl/touk/nussknacker/engine/spel/SpelExpressionSpec.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2288,6 +2288,19 @@ class SpelExpressionSpec extends AnyFunSuite with Matchers with ValidatedValuesD
22882288
Await.result(firstFailureOrCompletion, 15.seconds)
22892289
}
22902290

2291+
test("should evaluate spelTemplate without passing .toString on input") {
2292+
forAll(
2293+
Table(
2294+
("expression", "result"),
2295+
("#{ #mapValue } #{ #obj }", "{foo=bar} Test(1,2,[Test(3,4,[],0), Test(5,6,[],0)],4187338076)"),
2296+
("#{ #mapValue }", "{foo=bar}"),
2297+
)
2298+
) { (expression, result) =>
2299+
val parsed = parse[String](expr = expression, flavour = SpelExpressionParser.Template).validValue
2300+
parsed.evaluateSync[String]() shouldBe result
2301+
}
2302+
}
2303+
22912304
}
22922305

22932306
case class SampleObject(list: java.util.List[SampleValue])

0 commit comments

Comments
 (0)