diff --git a/docs/Changelog.md b/docs/Changelog.md index 54713ea814a..117b5b6a355 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -62,7 +62,7 @@ * [#6925](https://github.com/TouK/nussknacker/pull/6925) Fix situation when preset labels were presented as `null` when node didn't pass the validation. * [#6935](https://github.com/TouK/nussknacker/pull/6935) Spel: Scenario labels added to meta variable - `#meta.scenarioLabels` * [#6952](https://github.com/TouK/nussknacker/pull/6952) Improvement: TypeInformation support for scala.Option -* [#6840](https://github.com/TouK/nussknacker/pull/6840) Introduce castTo and canCastTo extension methods in SpeL. +* [#6840](https://github.com/TouK/nussknacker/pull/6840) Introduce canCastTo, castTo and castToOrNull extension methods in SpeL. ## 1.17 diff --git a/scenario-compiler/src/main/java/pl/touk/nussknacker/engine/spel/internal/RuntimeConversionHandler.java b/scenario-compiler/src/main/java/pl/touk/nussknacker/engine/spel/internal/RuntimeConversionHandler.java index a7e4e7fa49c..73114d00c3f 100644 --- a/scenario-compiler/src/main/java/pl/touk/nussknacker/engine/spel/internal/RuntimeConversionHandler.java +++ b/scenario-compiler/src/main/java/pl/touk/nussknacker/engine/spel/internal/RuntimeConversionHandler.java @@ -6,6 +6,7 @@ import org.springframework.lang.Nullable; import pl.touk.nussknacker.engine.extension.Cast; import pl.touk.nussknacker.engine.extension.ExtensionMethods; +import scala.PartialFunction; import java.lang.reflect.Array; import java.lang.reflect.InvocationTargetException; @@ -42,17 +43,16 @@ public Object invoke(Method method, Object target, Object[] arguments, ClassLoader classLoader) throws IllegalAccessException, InvocationTargetException { - if (target != null && target.getClass().isArray() && method.getDeclaringClass().isAssignableFrom(List.class)) { + Class methodDeclaringClass = method.getDeclaringClass(); + if (target != null && target.getClass().isArray() && methodDeclaringClass.isAssignableFrom(List.class)) { return method.invoke(RuntimeConversionHandler.convert(target), arguments); + } + PartialFunction, Object> extMethod = + ExtensionMethods.invoke(method, target, arguments, classLoader); + if (extMethod.isDefinedAt(methodDeclaringClass)) { + return extMethod.apply(methodDeclaringClass); } else { - return ExtensionMethods.invoke(method, target, arguments, classLoader) - .applyOrElse(method.getDeclaringClass(), (ignored) -> { - try { - return method.invoke(target, arguments); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new RuntimeException(e); - } - }); + return method.invoke(target, arguments); } } } diff --git a/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/extension/Cast.scala b/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/extension/Cast.scala index 531a1935cf1..6f1909f8e74 100644 --- a/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/extension/Cast.scala +++ b/scenario-compiler/src/main/scala/pl/touk/nussknacker/engine/extension/Cast.scala @@ -31,7 +31,7 @@ class CastImpl(target: Any, classLoader: ClassLoader) extends Cast { } } - override def castToOrNull[T >: Null](className: String): T = Try { castTo(className) }.getOrElse(null) + override def castToOrNull[T >: Null](className: String): T = Try { castTo[T](className) }.getOrElse(null) } private[extension] object CastImpl extends ExtensionMethodsImplFactory { diff --git a/scenario-compiler/src/test/scala/pl/touk/nussknacker/engine/spel/SpelExpressionSpec.scala b/scenario-compiler/src/test/scala/pl/touk/nussknacker/engine/spel/SpelExpressionSpec.scala index 62869434179..0040221ee12 100644 --- a/scenario-compiler/src/test/scala/pl/touk/nussknacker/engine/spel/SpelExpressionSpec.scala +++ b/scenario-compiler/src/test/scala/pl/touk/nussknacker/engine/spel/SpelExpressionSpec.scala @@ -1494,6 +1494,22 @@ class SpelExpressionSpec extends AnyFunSuite with Matchers with ValidatedValuesD } } + test("should return null if castToOrNull fails") { + parse[Any]( + expr = "#unknownString.value.castToOrNull('java.lang.Integer')", + context = ctx, + methodExecutionForUnknownAllowed = true + ).validExpression.evaluateSync[Any](ctx) == null shouldBe true + } + + test("should castToOrNull succeed") { + parse[Any]( + expr = "#unknownString.value.castToOrNull('java.lang.String')", + context = ctx, + methodExecutionForUnknownAllowed = true + ).validExpression.evaluateSync[Any](ctx) shouldBe "unknown" + } + } case class SampleObject(list: java.util.List[SampleValue])