All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.twitter.util.validation.constraintvalidation.TwitterConstraintValidatorContext.scala Maven / Gradle / Ivy

The newest version!
package com.twitter.util.validation.constraintvalidation

import jakarta.validation.{ConstraintValidatorContext, Payload, ValidationException}
import org.hibernate.validator.constraintvalidation.HibernateConstraintValidatorContext

object TwitterConstraintValidatorContext {

  def builder: TwitterConstraintValidatorContext.Builder =
    new Builder(None, None, Map.empty[String, AnyRef], Map.empty[String, AnyRef])

  /**
   * Simple utility to build a non-default [[jakarta.validation.ConstraintViolation]]
   * from a [[jakarta.validation.ConstraintValidatorContext]].
   */
  class Builder private[validation] (
    messageTemplate: Option[String],
    payload: Option[Payload],
    messageParameters: Map[String, AnyRef],
    expressionVariables: Map[String, AnyRef]) {

    /**
     * Specify a new un-interpolated constraint message.
     *
     * @param messageTemplate an un-interpolated constraint message.
     *
     * @return a [[TwitterConstraintValidatorContext.Builder]] to allow for method chaining.
     */
    def withMessageTemplate(messageTemplate: String): Builder =
      new Builder(
        messageTemplate = Some(messageTemplate),
        payload = this.payload,
        messageParameters = this.messageParameters,
        expressionVariables = this.expressionVariables)

    /**
     * Allows to set an object that may further describe the violation. The user is responsible to
     * ensure that this payload is serializable in case the [[jakarta.validation.ConstraintViolation]]
     * has to be serialized.
     *
     * @param payload payload an object representing additional information about the violation
     *
     * @return a [[TwitterConstraintValidatorContext.Builder]] to allow for method chaining.
     */
    def withDynamicPayload(payload: Payload): Builder =
      new Builder(
        messageTemplate = this.messageTemplate,
        payload = Some(payload),
        messageParameters = this.messageParameters,
        expressionVariables = this.expressionVariables)

    /**
     * Allows setting of an additional named parameter which can be interpolated in the constraint violation message. The
     * variable will be available for interpolation for all constraint violations generated for this constraint.
     * This includes the default one as well as all violations created by this TwitterConstraintValidatorContext.
     * To create multiple constraint violations with different variable values, this method can be called
     * between successive calls to [[TwitterConstraintValidatorContext#addConstraintViolation]].
     *
     * @param name the name under which to bind the parameter, cannot be `null`.
     * @param value the value to be bound to the specified name
     *
     * @return a [[TwitterConstraintValidatorContext.Builder]] to allow for method chaining.
     */
    def addMessageParameter(name: String, value: AnyRef): Builder =
      new Builder(
        messageTemplate = this.messageTemplate,
        payload = this.payload,
        messageParameters = this.messageParameters + (name -> value),
        expressionVariables = this.expressionVariables
      )

    /**
     * Allows setting of an additional expression variable which will be available as an EL variable during interpolation. The
     * variable will be available for interpolation for all constraint violations generated for this constraint.
     * This includes the default one as well as all violations created by this TwitterConstraintValidatorContext.
     * To create multiple constraint violations with different variable values, this method can be called
     * between successive calls to [[TwitterConstraintValidatorContext#addConstraintViolation]].
     *
     * @param name the name under which to bind the expression variable, cannot be `null`.
     * @param value the value to be bound to the specified name
     *
     * @return a [[TwitterConstraintValidatorContext.Builder]] to allow for method chaining.
     */
    def addExpressionVariable(name: String, value: AnyRef): Builder =
      new Builder(
        messageTemplate = this.messageTemplate,
        payload = this.payload,
        messageParameters = this.messageParameters,
        expressionVariables = this.expressionVariables + (name -> value)
      )

    /**
     * Replaces the default constraint violation report with one built via this method using the
     * given [[TwitterConstraintValidatorContext]].
     *
     * @param context the [[TwitterConstraintValidatorContext]] to use in building a [[jakarta.validation.ConstraintViolation]]
     *
     * @throws ValidationException - if the given [[TwitterConstraintValidatorContext]] cannot be unwrapped as expected.
     */
    @throws[ValidationException]
    def addConstraintViolation(context: ConstraintValidatorContext): Unit = {
      if (context != null) {
        val hibernateContext: HibernateConstraintValidatorContext =
          context.unwrap(classOf[HibernateConstraintValidatorContext])
        // custom payload
        payload.foreach(hibernateContext.withDynamicPayload)
        // set message parameters
        messageParameters.foreach {
          case (name, value) =>
            hibernateContext.addMessageParameter(name, value)
        }
        // set expression variables
        expressionVariables.foreach {
          case (name, value) =>
            hibernateContext.addExpressionVariable(name, value)
        }
        // custom message
        messageTemplate.foreach { template =>
          hibernateContext.disableDefaultConstraintViolation()

          if (expressionVariables.nonEmpty) {
            hibernateContext
              .buildConstraintViolationWithTemplate(template)
              .enableExpressionLanguage
              .addConstraintViolation()
          } else {
            hibernateContext
              .buildConstraintViolationWithTemplate(template)
              .addConstraintViolation()
          }
        }
      }
    }
  }

  /**
   * Specify a new un-interpolated constraint message.
   *
   * @param messageTemplate an un-interpolated constraint message.
   *
   * @return a [[TwitterConstraintValidatorContext.Builder]] to allow for method chaining.
   */
  def withMessageTemplate(messageTemplate: String): TwitterConstraintValidatorContext.Builder =
    builder.withMessageTemplate(messageTemplate)

  /**
   * Allows to set an object that may further describe the violation. The user is responsible to
   * ensure that this payload is serializable in case the [[jakarta.validation.ConstraintViolation]]
   * has to be serialized.
   *
   * @param payload payload an object representing additional information about the violation
   *
   * @return a [[TwitterConstraintValidatorContext.Builder]] to allow for method chaining.
   */
  def withDynamicPayload(payload: Payload): TwitterConstraintValidatorContext.Builder =
    builder.withDynamicPayload(payload)

  /**
   * Allows setting of an additional named parameter which can be interpolated in the constraint violation message. The
   * variable will be available for interpolation for all constraint violations generated for this constraint.
   * This includes the default one as well as all violations created by this TwitterConstraintValidatorContext.
   * To create multiple constraint violations with different variable values, this method can be called
   * between successive calls to [[TwitterConstraintValidatorContext#addConstraintViolation]]. E.g.,
   * within a ConstraintValidator instance:
   * {{{
   *   def isValid(value: String, constraintValidatorContext: TwitterConstraintValidatorContext): Boolean = {
   *
   *     TwitterConstraintValidatorContext
   *       .addMessageParameter("foo", "bar")
   *       .withMessageTemplate("{foo}")
   *       .addConstraintViolation(context)
   *
   *     TwitterConstraintValidatorContext
   *       .addMessageParameter("foo", "snafu")
   *       .withMessageTemplate("{foo}")
   *       .addConstraintViolation(context)
   *
   *    false
   * }}}
   *
   * @param name the name under which to bind the parameter, cannot be `null`.
   * @param value the value to be bound to the specified name
   *
   * @return a [[TwitterConstraintValidatorContext.Builder]] to allow for method chaining.
   */
  def addMessageParameter(name: String, value: AnyRef): TwitterConstraintValidatorContext.Builder =
    builder.addMessageParameter(name, value)

  /**
   * Allows setting of an additional expression variable which will be available as an EL variable during interpolation. The
   * variable will be available for interpolation for all constraint violations generated for this constraint.
   * This includes the default one as well as all violations created by this TwitterConstraintValidatorContext.
   * To create multiple constraint violations with different variable values, this method can be called
   * between successive calls to [[TwitterConstraintValidatorContext#addConstraintViolation]]. E.g.,
   * within a ConstraintValidator instance:
   * {{{
   *   def isValid(value: String, constraintValidatorContext: TwitterConstraintValidatorContext): Boolean = {
   *
   *     TwitterConstraintValidatorContext
   *       .addExpressionVariable("foo", "bar")
   *       .withMessageTemplate("${foo}")
   *       .addConstraintViolation(context)
   *
   *     TwitterConstraintValidatorContext
   *       .addExpressionVariable("foo", "snafu")
   *       .withMessageTemplate("${foo}")
   *       .addConstraintViolation(context)
   *
   *    false
   * }}}
   *
   * @param name the name under which to bind the expression variable, cannot be `null`.
   * @param value the value to be bound to the specified name
   *
   * @return a [[TwitterConstraintValidatorContext.Builder]] to allow for method chaining.
   */
  def addExpressionVariable(
    name: String,
    value: AnyRef
  ): TwitterConstraintValidatorContext.Builder =
    builder.addExpressionVariable(name, value)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy