DSL Validations: Operators

Thumbnail 11

This is part 3 of a 4-part series.

  • Part 1: DSL Validations: Properties
  • Part 2:DSL Validations: Child Properties

Operators provide a value for validating properties as a single unit: think of a multi-part conditional check in an if statement. The most obvious operators are logical AND (&&) and OR (!!kotlin programming language online compiler), though other operators are possdata computing ebookible.

Implementing Opdata computing wikipediaerators

Operatokotlin programming language tutorialrs are themselves validators, imdomain-specific languageplementing the same fun vadata computing ebooklidate(): Boolean as property validators but instead evaluates one or more validators to detedomain-specific languages pdfrmine overall sdata computing definitionuccess or failure, e.g. all pass validations for AND or at least one passes validation for OR.

AbstractOperator

Each impldata computing definitionemented operatokotlin programming language documentationr extends AbstractOperator to ensure correct equals and hashCode methods exist, similar to AbstractPropertyValidator. Instead ofdomain-specific language model a getter provided during construction, an operator is provided a collection of Provalve operator extensionpertyOperatorValidator's againstdata center cloud computing which the orange extension operatorperator is applied.

Kotlin

<div class="codeMirror-code--wrarange extension operator armypper" data-code="abstract class AbstractOperc# operator overloading extension methodator (
protected val conditionName: String,
protected val validators: List<PropertyOperatorValidator>) :domain-specific languages pdf
AbstractValidator() {
override fun equals(other: Any?): Boolean {
ic# operator overloading extensionf (this === other) return true
if (javaClass != other?.javaClass) return false
other as AbstractOperatorValidator
if (conditionName != other.conditionName) return false
return true
}
override fun hashCode(): Int {
return Objects.hashkotlin programming language online compiler(conditionName)
}
}" ddomain-specific language wikipediaata-lang=data center cloud computing"text/x-kotlin">

abstract class AbstractOperator<S> (
    protected val conditionName: String,
    protected val validators: List<PropertyOperatorValidator<S>>) :
    AbstractValidator<S>() {
    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (javaClass != other?.javaClass) return false
        other as AbstractOperatorValidator<*>
        if (conditionName != other.conditionName) return false
        return true
    }
    override fun hashCode(): Int {
        return Objects.hash(conditionName)
    }
}

Propeoperator extension 3cxrty validators andata computing ebookddata computing kaplan operators bothdata computing wikipedia implement PropertyOperatorValidarange extension operatortor vdata computing definitionia AbstractValidator which allows an operator to recursively evaluate operators, similar to using parentheses to define sub-conditdata computing wikipediaions within in the overall conditional.

AndOperator/OrOperator

Logical operatordomain-specific language in writings are constructed with the following parameters

  • conditionName: descoperator expansionriptive name of the operator's purpose or intdata computing ebookent;
  • validators: a collection of validators thrange extension operatorat are evaluated by the operator;
  • errorMessage: the error message provided in the ConstraintViolation; otdomain-specific language in writingherwise, constraint violatkotlin programming language code samplesions are created for each validator evaluated.

An operator-specific error message often provides bettdomain-specific language definitioner context than individual messages for each failecloud computing data protectiond condition, such as Both first and last names required. instead of firstNamerequirkotlin programming language online compilered; lastName required.

Kotlin

<div class="codeMirror-code--wc# operator overloading extensionrapper" data-code="class AndOpdata computing wikipediaerator(conditionNbig data cloud computingame: String,
validators: List<PropertyValidatcloud computing data center architectureor>,
val edata computing definitionrrorMedata computing definitionssage: String? = nrange extension operatorull) :
AbstractOperator(conditionName, validators) {
override fun validate(
source: S,
errors: MutableSecloud computing data center architecturet<ConstraintViolation>): Boolean {
val errorsTkotlin programming language online compileroUse =
if (cloud computing data center architectureerrorMessage.isNullOrBlank())
errodata computing wikipediars
else
mutableSetOf(data computing wikipedia)
val success = validatokotlin programming language documentationrs.all {
it.validate(source, errorsToUse)
}
if (!success && !erroperator expansionorMesskotlin programming language documentationagedata computing definition.isNullOrBlank()) {data computing wikipedia
addViolation(
source,
errorMessage,
errorMessage,
conditionName,
null,
errors)
}
return success
}
}" data-lang="text/x-kotlin"&cloud computing data center architecturegt;

class AndOperator<S>(conditionName: String,
                     validators: List<PropertyValidator<S>>,
                     val errorMessage: String? = null) :
    AbstractOperator<S>(conditionName, validators) {
    override fun validate(
        source: S,
        errors: MutableSet<ConstraintViolation<S>>): Boolean {
        val errorsToUse =
            if (errorMessage.isNullOrBlank())
                errors
            else
                mutableSetOf()
        val success = validators.all {
            it.validate(source, errorsToUse)
        }
        if (!success && !errorMessage.isNullOrBlank()) {
            addViolation(
                source,
                errorMessage,
                errorMessage,
                conditionName,
                null,
                errors)
        }
        return success
    }
}

The only changdata computing wikipediae required to implement OrOperator is that only one validator must pass validation.

Kotlindata computing definition
val success = validators.any {
    it.validate(source, errorsToUse)
}

Putting It All Together

For example, social-planning, an Invitee is the person being invited. The state of an invitee is INVITED, ACCEPTED, or DECLINED.

Kotlin
data class Invitee {
   val state: InviteeState,
   val firstName: String?,
   val lastName: String?,
   val emailAddress: String,
   val howMany: Int?
}

When accepdomain-specific language in writingting or declining the invitation, the user provides her name. For accepted invitations, she indicates how madomain-specific language in writingny people are attending (e.g., the invitee herself, padomain-specific language modelrtner or spouse, children, friends, etc.). Otherwise, the optional properties are not required.

General Progoperator expansionraming Implementation

Kotlin

<div class="codeMirror-code--wrapper" data-code=&operator extension 3cxqdomain-specific language in writinguot;val invitee = getInkotlin programming language pdfvitee(...)
if (invitee.statkotlin programming language downloade == InviteeState.INVITED) return true
if (invite.firstName.isNullOrBlank() || invite.lastrange extension operator armyName.isNullOrBlank()) {domain-specific language dsl
log.warn("First and last name required.")
return false
}
if (invitee.state == InviteeState.ACCEPTED && howMany 😕 0

val invitee = getInvitee(...)
if (invitee.state == InviteeState.INVITED) return true
if (invite.firstName.isNullOrBlank() || invite.lastName.isNullOrBlank()) {
    log.warn("First and last name required.")
    return false
}
if (invitee.state == InviteeState.ACCEPTED && howMany :? 0 <= 0) {
    log.warn("Must specify how many people expected to attend.")
    return false
}
return true

Domadomain-specific language definitionin-Spedata center cloud computingcific Languac# operator overloading extensionge Solution

Kotlin

<div class="codeMirror-code--wrapper" dkotlin programming language downloadata-code="val invitee = getIdata computing wikipedianvitee(..domain-specific languages pdf.)
// howMany rdata computing kaplanequired when invitation accepted
val accepted = OrOperator(
conditionName = "acceptedHowMany&data computing wikipediaquot;,
errorMessage = "Must specify number of attoperator expansionenkotlin programming language tutorialdees when accepting.domain-specific language definition&quodomain-specific languaget;,
validabig data cloud computingtors = setOf(
EnumNvalve operator extensionodomain-specific language examplestEqualsValidator(
propertyName = &quotoperator extension;state",
getter = Invitee::stage,
value = InviteeState.ACCEPTED),
PositiveIntekotlin programming language logogerValidkotlin programming language pdfakotlin programming language downloadtor(
propertyName = "howMany",c# operator overloading extension method
gettekotlin programming language online compilerr = Invitee::howMany)
)
)
// Invitee must provide first/last name when accepticloud computing data protectionng/declining invite
val responded = OrOperator(
conditionName = "inviteReply",
errorMekotlin programming language documentationssage = "First and last name required when accepted/declined.",
valikotlin programming language code samplesdators = setOf(
EnumNotEqualsValidatorrange extension operator(
prkotlin programming language logoopertyName = "state",
getter = Invitee::stagdata computing ebooke,
value = InviteeState.INVITED
),
Adomain-specific language definitionndOperator (
conditionName = "allPresent",
errorMessage = null,
validators = setOf(
StringNotBlankValidator("firstName", Invitee::firstName),
StringNotBlankValidator("lastName", Invitee::lastName),
)
)
)
)
// Both of the above must be truekotlin programming language documentation
val operator = AndOperator (
propertyName = "invidata computing wikipediateeValidation",
validators = setOf (accepted, responded)domain-specific language examples
)
// Validate the complete operator
val violations = mutableSetOf<ConstraintViolatcloud computing data center architectureion>(operator extension)
operator.validate(invitee, violations)
// empty collection means succdomain-specific languages pdfessful validation
val successfullyValidated = vioc# operator overloading extensionlations.isEmpty()" data-lang="tedata computing kaplanxt/x-kotlin">

val invitee = getInvitee(...)
// howMany required when invitation accepted
val accepted = OrOperator(
    conditionName = "acceptedHowMany",
    errorMessage = "Must specify number of attendees when accepting.",
    validators = setOf(
        EnumNotEqualsValidator(
          propertyName = "state",
          getter = Invitee::stage,
          value = InviteeState.ACCEPTED),
        PositiveIntegerValidator(
          propertyName = "howMany", 
          getter = Invitee::howMany)
   )
)
// Invitee must provide first/last name when accepting/declining invite
val responded = OrOperator(
    conditionName = "inviteReply",
    errorMessage = "First and last name required when accepted/declined.",
    validators = setOf(
        EnumNotEqualsValidator(
          propertyName = "state",
          getter = Invitee::stage,
          value = InviteeState.INVITED
        ),
        AndOperator (
          conditionName = "allPresent",
          errorMessage = null,
          validators = setOf(
            StringNotBlankValidator("firstName", Invitee::firstName),
            StringNotBlankValidator("lastName", Invitee::lastName),
          )
       )
   )
)
// Both of the above must be true
val operator = AndOperator (
   propertyName = "inviteeValidation",
   validators = setOf (accepted, responded)
)
// Validate the complete operator
val violations = mutableSetOf<ConstraintViolation<T>>()
operator.validate(invitee, violations)
// empty collection means successful validation
val successfullyValidated = violations.isEmpty()

Comoperator expansionparison

Though the general implementation is shorter, is it a better implementation? Some advantages of validating via the DSL are:

Final Comments

DSL obig data cloud computingperadomain-specific language wikipediators allow us to implement more complex and useful validoperator extensionators, much beyond what is possible with property-level annotations/data computing ebookvalidators (e.g., @NotBlank, @Ndata computing kaplanotoperator extensionNull, @Email, etc). The final step is to wraoperator expansionp this with a true Jakarta Bean Validator tkotlin programming language code sampleshat can berange extension operator used to voperator extensionalidate a complete bean.

Image 1991 Scott C Sokotlin programming language online compilersna