1
votes

I am trying to create a validator for reads that will only allow a valid email or an empty string.

What I tried until now seem to work only partially. Here is my reads defenition:

case class EmailFieldValueForm(value: String) extends FieldValueForm

val emailFieldValueFormReads: Reads[EmailFieldValueForm] =
    (__ \ "value").read[String](email or maxLength(0)).map(EmailFieldValueForm.apply _)

When I test it, I am getting the following error:

diverging implicit expansion for type play.api.libs.json.Reads[V] [error] starting with value uuidReads in trait DefaultReads [error]
(__ \ "value").read[String](email or maxLength(0)).map(EmailFieldValueForm.apply _)

Also, tried doing it with regex:

val emailFieldValueFormReads: Reads[EmailFieldValueForm] =
    (__ \ "value").read[String](email or pattern("""^$"""r)).map(EmailFieldValueForm.apply)

And in this case, any json I provide is passing.For example:

val invalidJson = Json.parse(
        """
          |{
          | "value": "boo"
          |}
        """.stripMargin

Simply gives me an empty value, but does not fail validation.

What am I doing wrong?

Thanks,

SOLUTION Seems like I was not doing the testing correctly. The following worked:

val invalidJson = Json.parse(
        """
          |{
          | "value": "boo"
          |}
        """.stripMargin
      )

      (EmailFieldValueForm.emailFieldValueFormReads reads invalidJson match {
        case JsSuccess(value, _) => value
        case JsError(e) => throw JsResultException(e)
      }) must throwA[JsResultException]
1

1 Answers

1
votes

The problem lies in implicit reads: Reads[M] for def maxLength[M](m: Int)(implicit reads: Reads[M], p: M => scala.collection.TraversableLike[_, M])

You may specify type M explicitly and all will be fine

import play.api.libs.functional.syntax._
import play.api.libs.json.Reads._
import play.api.libs.json._

val emailFieldValueFormReads: Reads[EmailFieldValueForm] =
  ((__ \ "value").read[String](email or maxLength[String](0))).map(EmailFieldValueForm.apply _)

Json.parse("""{"value": "sss"}""").validate[EmailFieldValueForm](emailFieldValueFormReads)
Json.parse("""{"value": ""}""").validate[EmailFieldValueForm](emailFieldValueFormReads)
Json.parse("""{"value": "[email protected]"}""").validate[EmailFieldValueForm](emailFieldValueFormReads)

scala> res0: play.api.libs.json.JsResult[EmailFieldValueForm] = JsError(List((/value,List(ValidationError(List(error.email),WrappedArray()), ValidationError(List(error.maxLength),WrappedArray(0))))))

scala> res1: play.api.libs.json.JsResult[EmailFieldValueForm] = JsSuccess(EmailFieldValueForm(),/value)

scala> res2: play.api.libs.json.JsResult[EmailFieldValueForm] = JsSuccess(EmailFieldValueForm([email protected]),/value)

For testing with scalatest (PlaySpec) you may use

Json.parse("""{"value": "sss"}""").validate[EmailFieldValueForm](emailFieldValueFormReads) must be an 'error
Json.parse("""{"value": "[email protected]"}""").validate[EmailFieldValueForm](emailFieldValueFormReads) must be an 'success
Json.parse("""{"value": ""}""").validate[EmailFieldValueForm](emailFieldValueFormReads) must be an 'success