Skip to content

Commit 65b981e

Browse files
szegedijenkins
authored and
jenkins
committed
scrooge-generator: Make Field class annotation flag always consistent; make sure we don't miss custom validations
Problem: -------- Scrooge AST `Field.hasValidationAnnotation` can be set independently of `Field.fieldAnnotations`, creating instances in inconsistent state. Further, it will miss custom annotations unless we enforce that custom annotations also must have the `validation.` prefix. Solution: --------- Make `Field.hasValidationAnnotation` a computed field that is always consistent with the value in `Field.fieldAnnotations`. Enforce that custom annotations must start with the `validation.` prefix. JIRA Issues: CSL-12123 Differential Revision: https://phabricator.twitter.biz/D912077
1 parent 4ebb586 commit 65b981e

File tree

8 files changed

+33
-32
lines changed

8 files changed

+33
-32
lines changed

CHANGELOG.rst

+11
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,23 @@ Note that ``PHAB_ID=#`` and ``RB_ID=#`` correspond to associated messages in com
77
Unreleased
88
----------
99

10+
Breaking API Changes
11+
~~~~~~~~~~~~~~~~~~~~
12+
13+
* scrooge-generator: `c.t.scrooge.ast.Field.hasValidationAnnotation` field can no longer
14+
be set in the constructor, but it is now a property derived from the value in the
15+
`Field.fieldAnnotations` field; if any annotations have a name starting with `validation.`
16+
it is set to true, otherwise it is false. ``PHAB_ID=D912077``
17+
1018
Runtime Behavior Changes
1119
~~~~~~~~~~~~~~~~~~~~~~~~
1220

1321
* scrooge-generator: Move `ServerValidationMixin` trait to be in the companion object of the service, this is to
1422
avoid ambiguities when calling the trait from inherited services. ``PHAB_ID=D943975``
1523

24+
* scrooge-thrift-validation: custom annotations in `ThriftValidator` must have a
25+
name starting with `validation.` ``PHAB_ID=D912077``
26+
1627
22.7.0
1728
------
1829

scrooge-core/src/main/scala/com/twitter/scrooge/UtilValidator.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ object UtilValidator {
2424
*/
2525
final class UtilValidator extends BaseValidator {
2626

27-
override def annotations: Set[String] = DefaultAnnotations.metadata.keySet
27+
override def annotations: Set[String] = DefaultAnnotations.keys
2828

2929
// validate each field value for default annotations defined on
3030
// this field.

scrooge-generator-tests/src/test/scala/com/twitter/scrooge/frontend/TypeResolverSpec.scala

-2
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,6 @@ class TypeResolverSpec extends Spec {
410410
_,
411411
_,
412412
_,
413-
_,
414413
_
415414
) => // pass
416415
case _ => fail()
@@ -425,7 +424,6 @@ class TypeResolverSpec extends Spec {
425424
_,
426425
_,
427426
_,
428-
_,
429427
_
430428
) => // pass
431429
case _ => fail()

scrooge-generator/src/main/scala/com/twitter/scrooge/AST/Node.scala

+7-3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package com.twitter.scrooge.ast
1717

18+
import com.twitter.scrooge.thrift_validation.ThriftValidator
1819
import scala.util.parsing.input.Positional
1920

2021
sealed abstract class Node extends Positional
@@ -66,9 +67,12 @@ case class Field(
6667
requiredness: Requiredness = Requiredness.Default,
6768
typeAnnotations: Map[String, String] = Map.empty,
6869
fieldAnnotations: Map[String, String] = Map.empty,
69-
docstring: Option[String] = None,
70-
hasValidationAnnotation: Boolean = false)
71-
extends Node
70+
docstring: Option[String] = None)
71+
extends Node {
72+
73+
val hasValidationAnnotation =
74+
fieldAnnotations.keysIterator.exists(ThriftValidator.isValidationAnnotationName)
75+
}
7276

7377
case class Function(
7478
funcName: SimpleID,

scrooge-generator/src/main/scala/com/twitter/scrooge/frontend/ThriftParser.scala

+1-2
Original file line numberDiff line numberDiff line change
@@ -237,8 +237,7 @@ class ThriftParser(
237237
transformedReq,
238238
typeAnnotations,
239239
fieldAnnotations,
240-
comm,
241-
fieldAnnotations.keySet.exists(_.startsWith("validation."))
240+
comm
242241
)
243242
}
244243
)

scrooge-generator/src/main/scala/com/twitter/scrooge/java_generator/FunctionController.scala

+1-2
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,7 @@ class FunctionController(
8585
fieldType = a.fieldType,
8686
default = a.default,
8787
requiredness = requiredness,
88-
fieldAnnotations = a.fieldAnnotations,
89-
hasValidationAnnotation = a.fieldAnnotations.keySet.exists(_.startsWith("validation."))
88+
fieldAnnotations = a.fieldAnnotations
9089
)
9190
}
9291
val structName = function.funcName.name + "_args"

scrooge-thrift-validation/src/main/scala/com/twitter/scrooge/thrift_validation/DefaultAnnotations.scala

+2
Original file line numberDiff line numberDiff line change
@@ -132,4 +132,6 @@ object DefaultAnnotations {
132132
),
133133
"validation.UUID" -> AnnotationMetaData(None, Set(classOf[String]), classOf[UUID])
134134
)
135+
136+
private[twitter] val keys = metadata.keySet
135137
}

scrooge-thrift-validation/src/main/scala/com/twitter/scrooge/thrift_validation/ThriftValidator.scala

+10-22
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,15 @@
11
package com.twitter.scrooge.thrift_validation
22

33
import com.twitter.scrooge.thrift_validation.ThriftValidator.DefaultAnnotationKeys
4+
import com.twitter.scrooge.thrift_validation.ThriftValidator.isValidationAnnotationName
45
import scala.collection.JavaConverters
56
import scala.collection.mutable
67

78
object ThriftValidator {
8-
val DefaultAnnotationKeys: Set[String] = Set(
9-
"validation.assertFalse",
10-
"validation.assertTrue",
11-
"validation.countryCode",
12-
"validation.EAN",
13-
"validation.email",
14-
"validation.UUID",
15-
"validation.ISBN",
16-
"validation.length.min",
17-
"validation.length.max",
18-
"validation.max",
19-
"validation.min",
20-
"validation.negative",
21-
"validation.negativeOrZero",
22-
"validation.notEmpty",
23-
"validation.positive",
24-
"validation.positiveOrZero",
25-
"validation.size.min",
26-
"validation.size.max"
27-
)
9+
def isValidationAnnotationName(annName: String): Boolean =
10+
annName.startsWith("validation.")
11+
12+
val DefaultAnnotationKeys: Set[String] = DefaultAnnotations.keys
2813
}
2914

3015
/**
@@ -33,8 +18,11 @@ object ThriftValidator {
3318
abstract class ThriftValidator extends BaseValidator {
3419
// Do not allow to override default annotations since we have a different
3520
// set of rules for default annotations and they are done before performing
36-
// custom validations.
37-
require(customAnnotations.keySet.intersect(DefaultAnnotationKeys).isEmpty)
21+
// custom validations. All custom validations must have a name that starts
22+
// with "validation."
23+
require(customAnnotations.keysIterator.forall { name =>
24+
isValidationAnnotationName(name) && !DefaultAnnotationKeys.contains(name)
25+
})
3826

3927
/**
4028
* A map of String annotations to [[ThriftConstraintValidator]].

0 commit comments

Comments
 (0)