in util-validator/src/main/scala/com/twitter/util/validation/ScalaValidator.scala [1029:1096]
private[this] def validateCascadedProperty[T](
context: ValidationContext[T],
propertyDescriptor: PropertyDescriptor,
clazzInstance: Any,
groups: Seq[Class[_]]
): Set[ConstraintViolation[T]] = propertyDescriptor.cascadedScalaType match {
case Some(cascadedScalaType) =>
// Update the found value with the current landscape, for example, the retrieved case class
// descriptor may be scala type Foo, but this property is a Seq[Foo] or an Option[Foo] and
// we want to carry that property typing through.
val caseClassDescriptor =
descriptorFactory
.describe[T](cascadedScalaType.erasure.asInstanceOf[Class[T]])
.copy(scalaType = propertyDescriptor.scalaType)
val caseClassPath = PathImpl.createCopy(context.path)
caseClassDescriptor.scalaType match {
case argType if argType.isCollection =>
val results = mutable.ListBuffer[ConstraintViolation[T]]()
val collectionValue: Iterable[_] = clazzInstance.asInstanceOf[Iterable[_]]
val collectionValueIterator = collectionValue.iterator
var index = 0
while (collectionValueIterator.hasNext) {
val instanceValue = collectionValueIterator.next()
// apply the index to the parent path, then use this to recompute paths of members and methods
val indexedPropertyPath = {
val indexedPath = PathImpl.createCopyWithoutLeafNode(caseClassPath)
indexedPath.addPropertyNode(
s"${caseClassPath.getLeafNode.asString()}[${index.toString}]")
indexedPath
}
val violations = validate[T](
maybeDescriptor = Some(
caseClassDescriptor
.copy(
scalaType = caseClassDescriptor.scalaType.typeArgs.head,
members = caseClassDescriptor.members,
methods = caseClassDescriptor.methods
)
),
context = context.copy(path = indexedPropertyPath),
value = instanceValue,
groups = groups
)
if (violations.nonEmpty) results.appendAll(violations)
index += 1
}
if (results.nonEmpty) results.toSet
else Set.empty[ConstraintViolation[T]]
case argType if argType.isOption =>
val optionValue = clazzInstance.asInstanceOf[Option[_]]
validate[T](
maybeDescriptor = Some(
caseClassDescriptor.copy(scalaType = caseClassDescriptor.scalaType.typeArgs.head)),
context = context.copy(path = caseClassPath),
value = optionValue,
groups = groups
)
case _ =>
validate[T](
maybeDescriptor = Some(caseClassDescriptor),
context = context.copy(path = caseClassPath),
value = clazzInstance,
groups = groups
)
}
case _ => Set.empty[ConstraintViolation[T]]
}