Skip to content

Commit

Permalink
[NU-1656] Check for methods if property does not exist (#6778)
Browse files Browse the repository at this point in the history
* SpeL: Check for methods if property does not exist
* Add brackets if suggested method has not empty parameters
  • Loading branch information
lukasz-bigorajski authored Sep 6, 2024
1 parent cb7714d commit a51d594
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ const getNormalizedValue = (suggestion: ExpressionSuggestion): string => {
return `["${suggestion.methodName}"]`;
}
}
if (suggestion.parameters?.length > 0) {
return `${suggestion.methodName}()`;
}
return suggestion.methodName;
};

Expand Down
3 changes: 2 additions & 1 deletion docs/Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
* [#6716](https://github.com/TouK/nussknacker/pull/6716) Fix type hints for #COLLECTION.merge function.
* [#6695](https://github.com/TouK/nussknacker/pull/6680) From now on, arrays on UI are visible as lists but on a
background they are stored as it is and SpeL converts them to lists in a runtime.
* [#6750](https://github.com/TouK/nussknacker/pull/6750) Add varargs to `#COLLECTION.concat` and `#COLLECTION.merge`.
* [#6750](https://github.com/TouK/nussknacker/pull/6750) Add varargs to `#COLLECTION.concat` and `#COLLECTION.merge`.
* [#6778](https://github.com/TouK/nussknacker/pull/6778) SpeL: check for methods if a property for a given name does not exist.

1.17.0 (Not released yet)
-------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import pl.touk.nussknacker.engine.spel.SpelExpressionParseError.MissingObjectErr
UnresolvedReferenceError
}
import pl.touk.nussknacker.engine.spel.SpelExpressionParseError.OperatorError._
import pl.touk.nussknacker.engine.spel.SpelExpressionParseError.PartTypeError
import pl.touk.nussknacker.engine.spel.SpelExpressionParseError.{ArgumentTypeError, PartTypeError}
import pl.touk.nussknacker.engine.spel.SpelExpressionParseError.SelectionProjectionError.{
IllegalProjectionError,
IllegalSelectionError,
Expand Down Expand Up @@ -434,6 +434,7 @@ private[spel] class Typer(
case e: PropertyOrFieldReference =>
current.stackHead
.map(extractProperty(e, _))
.map(fallbackToCheckMethodsIfPropertyNotExists)
.getOrElse(invalid(NonReferenceError(e.toStringAST)))
.map(toNodeResult)
// TODO: what should be here?
Expand Down Expand Up @@ -730,6 +731,16 @@ private[spel] class Typer(
}
}

private def fallbackToCheckMethodsIfPropertyNotExists(typing: TypingR[TypingResult]): TypingR[TypingResult] =
typing.mapWritten(_.map {
case e: NoPropertyError =>
methodReferenceTyper.typeMethodReference(typer.MethodReference(e.typ, false, e.property, Nil)) match {
case Left(me: ArgumentTypeError) => me
case _ => e
}
case e => e
})

private def valid[T](value: T): TypingR[T] = Writer(List.empty[ExpressionParseError], value)

private def invalid[T](err: ExpressionParseError, fallbackType: TypingResult = Unknown): TypingR[TypingResult] =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -490,8 +490,15 @@ class SpelExpressionSpec extends AnyFunSuite with Matchers with ValidatedValuesD
}

test("return invalid type if PropertyOrFieldReference does not exists") {
val parsed = parse[Any]("#processHelper.unknownProperty", ctxWithGlobal)
val expectedValidation = Invalid("There is no property 'unknownProperty' in type: SampleGlobalObject")
parsed.isInvalid shouldBe true
parsed.leftMap(_.head).leftMap(_.message) shouldEqual expectedValidation
}

test("return invalid argument if arguments is not passed to method") {
val parsed = parse[Any]("#processHelper.add", ctxWithGlobal)
val expectedValidation = Invalid("There is no property 'add' in type: SampleGlobalObject")
val expectedValidation = Invalid("Mismatch parameter types. Found: add(). Required: add(Integer, Integer)")
parsed.isInvalid shouldBe true
parsed.leftMap(_.head).leftMap(_.message) shouldEqual expectedValidation
}
Expand Down Expand Up @@ -1328,6 +1335,15 @@ class SpelExpressionSpec extends AnyFunSuite with Matchers with ValidatedValuesD
.evaluateSync[Any](ctx) shouldBe Array(false, false)
}

test("should check if method exists as a fallback of not found property") {
parse[Any]("{1, 2}.contains", ctx).invalidValue.toList should matchPattern {
case ArgumentTypeError("contains", _, _) :: Nil =>
}
parse[Any]("{1, 2}.contain", ctx).invalidValue.toList should matchPattern {
case NoPropertyError(_, "contain") :: Nil =>
}
}

}

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

0 comments on commit a51d594

Please sign in to comment.