{"id":46,"date":"2012-04-08T17:41:08","date_gmt":"2012-04-08T21:41:08","guid":{"rendered":"http:\/\/localhost\/wordpress\/?p=46"},"modified":"2012-08-31T22:34:15","modified_gmt":"2012-09-01T02:34:15","slug":"jsr-303-validation-using-stackable-traits","status":"publish","type":"post","link":"https:\/\/sourcedelica.com\/blog\/2012\/04\/jsr-303-validation-using-stackable-traits\/","title":{"rendered":"Composing Traits and Declarative Validation"},"content":{"rendered":"<p>Scala&#8217;s traits are a nice fit for <a href=\"http:\/\/java.dzone.com\/articles\/bean-validation-and-jsr-303\">JSR-303 validation<\/a>. Here&#8217;s an example. Suppose we have a web service interface that has methods like:<\/p>\n<pre class=\"brush: scala\">@WebService\r\ntrait Notification {\r\n  def deleteTopic(apiKey: String, topicId: Long)\r\n  def getSubscriber(apiKey: String, userId: String): Subscriber\r\n  def unsubscribe(apiKey: String, userId: String, topicId: Long, context: SubscriptionContext)\r\n  \/\/...\r\n}<\/pre>\n<p>Notice that the methods share many but not all of the same parameters. For example, all of them take <code>apiKey<\/code>. Our validation code should be factored to handle common parameters independently. \u00a0JSR-303 supports this very well. However, we also want to return validation errors to the caller with names that correspond directly to the web service method parameters. For example, if <code>deleteTopic()<\/code> is called with an invalid <code>topicId<\/code>, we want to respond with a fault like:<\/p>\n<pre class=\"brush: xml\">&lt;soap:Envelope xmlns:soap=\"http:\/\/schemas.xmlsoap.org\/soap\/envelope\/\"&gt;\r\n   &lt;soap:Body&gt;\r\n      &lt;soap:Fault&gt;\r\n         &lt;faultcode&gt;soap:Client&lt;\/faultcode&gt;\r\n         &lt;faultstring&gt;Errors in request&lt;\/faultstring&gt;\r\n         &lt;errors&gt;\r\n           &lt;error&gt;\r\n             &lt;inputElement&gt;topicId&lt;\/inputElement&gt;\r\n             &lt;errorMessage&gt;99 is invalid&lt;\/errorMessage&gt;\r\n          &lt;\/error&gt;\r\n        &lt;\/errors&gt;\r\n      &lt;\/soap:Fault&gt;\r\n   &lt;\/soap:Body&gt;\r\n&lt;\/soap:Envelope&gt;<\/pre>\n<p>The parameter name\/validation error requirement would be a pain to handle in Java because the validation object would need to be composed as a hierarchy of individual objects. The hierarchy would be reflected in the validation errors and would have to be manually flattened before returning the errors to the caller.<\/p>\n<p>In our web service implementation we will validate the parameters by creating a flat object containing the method parameters as properties. \u00a0Then we will call\u00a0<code>throwFaultIfInvalid()<\/code>\u00a0which will validate the parameters and throw a Fault exception if there are errors. For example:<\/p>\n<pre class=\"brush: scala\">  def unsubscribe(apiKeyIn: String, userIdIn: String, topicIdIn: Long, context: SubscriptionContext) {\r\n    val cmd = new UnsubscribeCmd {\r\n      apiKey = apiKeyIn\r\n      userId = userIdIn\r\n      topicId = topicIdIn\r\n      subscriptionContext = context\r\n    }\r\n    throwFaultIfInvalid(cmd)\r\n\r\n    \/\/ Logic to do unsubscribe...\r\n  }<\/pre>\n<p>Above,\u00a0<code>cmd<\/code> is a stack of five validation traits on top of a base <code>Object<\/code>.<\/p>\n<pre class=\"brush: scala\">@UnsubscribeCmdValid\r\ntrait UnsubscribeCmd extends UserIdCmd with TopicIdCmd with SubscriptionContextCmd {\r\n  var subscription: Subscription = _\r\n}\r\n\r\n@UserIdValid\r\ntrait UserIdCmd extends ApiKeyCmd {\r\n  @NotEmpty var userId: String = _\r\n  lazy val subscriber: Option[Subscriber] = \/\/ findSubscriber(userId)\r\n}\r\n\r\n@TopicIdValid\r\ntrait TopicIdCmd extends ApiKeyCmd {\r\n  @NotZero var topicId: Long = _\r\n  lazy val topic: Option[Topic] = \/\/ findTopic(topicId)\r\n}\r\n\r\n@SubscriptionContextValid\r\ntrait SubscriptionContextCmd extends ApiKeyCmd {\r\n  @NullInvalid var subscriptionContext: SubscriptionContext = _\r\n}\r\n\r\n@ApiKeyValid\r\ntrait ApiKeyCmd {\r\n  @NotEmpty var apiKey: String = _\r\n  lazy val application: Option[Application] = \/\/ findApplication(apiKey)\r\n}<\/pre>\n<p>The validator for <code>UnsubscribeCmd<\/code> looks like:<\/p>\n<pre class=\"brush: scala\">class UnsubscribeCmdValidator extends Validator[UnsubscribeCmdValid, UnsubscribeCmd] {\r\n  @Autowired var subscriptionDao: SubscriptionDao = _\r\n\r\n  def isValid(obj: UnsubscribeCmd, context: ConstraintValidatorContext): Boolean = {\r\n\r\n    ifSome(for (subscriber  obj.subscription = subscription\r\n    }\r\n  }<\/pre>\n<p>Nice! Traits allow us to compose the validators together in a way that results in very clean validation objects and validation code.<\/p>\n<h4>Side note<\/h4>\n<p>Sadly, as of Scala 2.9 you can&#8217;t create custom JSR-303 annotations (like <code>@UnsubscribeCmdValid<\/code> above) which require <code>RetentionPolicy.RUNTIME<\/code> in Scala. Go, right now, and vote for <a href=\"https:\/\/issues.scala-lang.org\/browse\/SI-32\">SI-32<\/a>\u00a0so we don&#8217;t have to keep writing these in Java. \u00a0 Thank you for your support.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Scala&#8217;s traits are a nice fit for JSR-303 validation. Here&#8217;s an example. Suppose we have a web service interface that has methods like: @WebService trait Notification { def deleteTopic(apiKey: String, topicId: Long) def getSubscriber(apiKey: String, userId: String): Subscriber def unsubscribe(apiKey: String, userId: String, topicId: Long, context: SubscriptionContext) \/\/&#8230; } Notice that the methods share many [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"class_list":["post-46","post","type-post","status-publish","format-standard","hentry","category-scala","entry"],"_links":{"self":[{"href":"https:\/\/sourcedelica.com\/blog\/wp-json\/wp\/v2\/posts\/46","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sourcedelica.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sourcedelica.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sourcedelica.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/sourcedelica.com\/blog\/wp-json\/wp\/v2\/comments?post=46"}],"version-history":[{"count":52,"href":"https:\/\/sourcedelica.com\/blog\/wp-json\/wp\/v2\/posts\/46\/revisions"}],"predecessor-version":[{"id":457,"href":"https:\/\/sourcedelica.com\/blog\/wp-json\/wp\/v2\/posts\/46\/revisions\/457"}],"wp:attachment":[{"href":"https:\/\/sourcedelica.com\/blog\/wp-json\/wp\/v2\/media?parent=46"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sourcedelica.com\/blog\/wp-json\/wp\/v2\/categories?post=46"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sourcedelica.com\/blog\/wp-json\/wp\/v2\/tags?post=46"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}