in util-validator/src/main/scala/com/twitter/util/validation/ScalaValidator.scala [849:959]
private[this] def validateExecutableParameters[T](
executableDescriptor: ExecutableDescriptor,
root: Option[T],
leaf: Option[Any],
parameterValues: Array[Any],
parameterNames: Option[Array[String]],
groups: Seq[Class[_]]
): Set[ConstraintViolation[T]] = {
if (executableDescriptor.members.size != parameterValues.length)
throw new IllegalArgumentException(
s"Invalid number of arguments for method ${executableDescriptor.executable.getName}.")
val results = new mutable.ListBuffer[ConstraintViolation[T]]()
val parameters: Array[Parameter] = executableDescriptor.executable.getParameters
val parameterNamesList: Array[String] =
(parameterNames match {
case Some(names) =>
names
case _ =>
getExecutableParameterNames(executableDescriptor.executable)
}).map { maybeMangled =>
DescriptorFactory.unmangleName(
maybeMangled
) // parameter names are encoded since Scala 2.13.5
}
// executable parameter constraints
var index = 0
val parametersLength = parameterNamesList.length
while (index < parametersLength) {
val parameter = parameters(index)
val parameterValue = parameterValues(index)
// only for property path use to affect error reporting
val parameterName = parameterNamesList(index)
val parameterPath =
PathImpl.createPathForExecutable(getExecutableMetaData(executableDescriptor.executable))
parameterPath.addParameterNode(parameterName, index)
val propertyDescriptor = executableDescriptor.members(parameter.getName)
val validateFieldContext =
ValidationContext[T](
Some(parameterName),
Some(executableDescriptor.executable.getDeclaringClass.asInstanceOf[Class[T]]),
root,
leaf,
parameterPath)
val parameterViolations = validateField[T](
validateFieldContext,
propertyDescriptor,
parameterValue,
groups
)
if (parameterViolations.nonEmpty) results.appendAll(parameterViolations)
index += 1
}
results.toSet
// executable cross-parameter constraints
val crossParameterPath = PathImpl
.createPathForExecutable(getExecutableMetaData(executableDescriptor.executable))
crossParameterPath.addCrossParameterNode()
val constraints = executableDescriptor.annotations
index = 0
val constraintsLength = constraints.length
while (index < constraintsLength) {
val constraint = constraints(index)
val scalaType = Reflector.scalaTypeOf(parameterValues.getClass)
val validators =
findConstraintValidators(constraint.annotationType())
.filter(parametersValidationTargetFilter)
val validatorsIterator = validators.iterator
while (validatorsIterator.hasNext) {
val validator = validatorsIterator.next().asInstanceOf[ConstraintValidator[Annotation, _]]
val constraintDescriptor = constraintDescriptorFactory
.newConstraintDescriptor(
name = executableDescriptor.executable.getName,
clazz = scalaType.erasure,
declaringClazz = executableDescriptor.executable.getDeclaringClass,
annotation = constraint,
constrainedElementKind = ConstrainedElementKind.METHOD
)
if (groupsEnabled(constraintDescriptor, groups)) {
// initialize validator
validator.initialize(constraint)
val validateCrossParameterContext =
ValidationContext[T](
None,
Some(executableDescriptor.executable.getDeclaringClass.asInstanceOf[Class[T]]),
root,
leaf,
crossParameterPath)
results.appendAll(
isValid(
context = validateCrossParameterContext,
constraint = constraint,
scalaType = scalaType,
value = parameterValues,
constraintDescriptorOption = Some(constraintDescriptor),
validatorOption = Some(validator.asInstanceOf[ConstraintValidator[Annotation, Any]]),
groups = groups
)
)
}
}
index += 1
}
results.toSet
}