override def asJsError: Option[JsError] = Some()

in server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/EmailSetSerializer.scala [152:351]


      override def asJsError: Option[JsError] = Some(JsError(s"Value associated with $property is invalid: $cause"))
    }

    private case class MailboxAddition(id: MailboxId) extends EntryValidation

    private case class MailboxRemoval(id: MailboxId) extends EntryValidation

    private case class MailboxReset(ids: MailboxIds) extends EntryValidation

    private case class KeywordsReset(keywords: Keywords) extends EntryValidation

    private case class KeywordAddition(keyword: Keyword) extends EntryValidation

    private case class KeywordRemoval(keyword: Keyword) extends EntryValidation

  }

  private implicit val messageIdWrites: Writes[MessageId] = messageId => JsString(messageId.serialize)
  private implicit val messageIdReads: Reads[MessageId] = {
    case JsString(serializedMessageId) => Try(JsSuccess(messageIdFactory.fromString(serializedMessageId)))
      .fold(_ => JsError("Invalid messageId"), messageId => messageId)
    case _ => JsError("Expecting messageId to be represented by a JsString")
  }

  private implicit val mailboxIdsMapReads: Reads[Map[MailboxId, Boolean]] =
    Reads.mapReads[MailboxId, Boolean] {s => Try(mailboxIdFactory.fromString(s)).fold(e => JsError(e.getMessage), JsSuccess(_)) } (mapMarkerReads)

  private implicit val mailboxIdsReads: Reads[MailboxIds] = jsValue => mailboxIdsMapReads.reads(jsValue).map(
    mailboxIdsMap => MailboxIds(mailboxIdsMap.keys.toList))

  private implicit val emailSetUpdateReads: Reads[EmailSetUpdate] = {
    case o: JsObject => EmailSetUpdateReads.reads(o)
    case _ => JsError("Expecting a JsObject to represent an EmailSetUpdate")
  }

  private implicit val updatesMapReads: Reads[Map[UnparsedMessageId, JsObject]] =
    Reads.mapReads[UnparsedMessageId, JsObject] {string => refineV[IdConstraint](string)
      .fold(e => JsError(s"messageId needs to match id constraints: $e"),
        id => JsSuccess(UnparsedMessageId(id))) }

  private implicit val createsMapReads: Reads[Map[EmailCreationId, JsObject]] =
    Reads.mapReads[EmailCreationId, JsObject] {s => refineV[IdConstraint](s)
      .fold(e => JsError(s"email creationId needs to match id constraints: $e"),
        id => JsSuccess(EmailCreationId(id))) }

  private implicit val keywordReads: Reads[Keyword] = {
    case jsString: JsString => Keyword.parse(jsString.value)
      .fold(JsError(_),
        JsSuccess(_))
    case _ => JsError("Expecting a string as a keyword")
  }

  private implicit val keywordsMapReads: Reads[Map[Keyword, Boolean]] =
    Reads.mapReads[Keyword, Boolean] {string => Keyword.parse(string).fold(JsError(_), JsSuccess(_)) } (mapMarkerReads)
  private implicit val keywordsReads: Reads[Keywords] = jsValue => keywordsMapReads.reads(jsValue).flatMap(
    keywordsMap => STRICT_KEYWORDS_FACTORY.fromSet(keywordsMap.keys.toSet)
      .fold(e => JsError(e.getMessage), keywords => JsSuccess(keywords)))

  private implicit val blobIdWrites: Writes[BlobId] = Json.valueWrites[BlobId]
  private implicit val blobIdReads: Reads[BlobId] = {
    case JsString(string) => BlobId.of(string)
      .toEither.fold(
        e => JsError(s"blobId does not match Id constraints: $e"),
        blobId => JsSuccess(blobId))
    case _ => JsError("blobId needs to be represented by a JsString")
  }
  private implicit val unparsedMessageIdWrites: Writes[UnparsedMessageId] = Json.valueWrites[UnparsedMessageId]
  private implicit val unparsedMessageIdReads: Reads[UnparsedMessageId] = {
    case JsString(string) => refined.refineV[IdConstraint](string)
      .fold(
        e => JsError(s"messageId does not match Id constraints: $e"),
        id => JsSuccess(UnparsedMessageId(id)))
    case _ => JsError("messageId needs to be represented by a JsString")
  }
  private implicit val unitWrites: Writes[Unit] = _ => JsNull
  private implicit val updatedWrites: Writes[Map[MessageId, Unit]] = mapWrites[MessageId, Unit](_.serialize, unitWrites)
  private implicit val notDestroyedWrites: Writes[Map[UnparsedMessageId, SetError]] = mapWrites[UnparsedMessageId, SetError](_.id.value, setErrorWrites)
  private implicit val destroyIdsReads: Reads[DestroyIds] = Json.valueFormat[DestroyIds]
  private implicit val destroyIdsWrites: Writes[DestroyIds] = Json.valueWrites[DestroyIds]
  private implicit val emailRequestSetReads: Reads[EmailSetRequest] = Json.reads[EmailSetRequest]
  private implicit val threadIdWrites: Writes[ThreadId] = Json.valueWrites[ThreadId]
  private implicit val emailCreationResponseWrites: Writes[EmailCreationResponse] = Json.writes[EmailCreationResponse]
  private implicit val createsMapWrites: Writes[Map[EmailCreationId, EmailCreationResponse]] =
    mapWrites[EmailCreationId, EmailCreationResponse](_.id.value, emailCreationResponseWrites)
  private implicit val notCreatedMapWrites: Writes[Map[EmailCreationId, SetError]] =
    mapWrites[EmailCreationId, SetError](_.id.value, setErrorWrites)

  private implicit val stateWrites: Writes[UuidState] = Json.valueWrites[UuidState]
  private implicit val emailResponseSetWrites: OWrites[EmailSetResponse] = Json.writes[EmailSetResponse]

  private implicit val subjectReads: Reads[Subject] = Json.valueReads[Subject]
  private implicit val emailerNameReads: Reads[EmailerName] = Json.valueReads[EmailerName]
  private implicit val headerMessageIdReads: Reads[HeaderMessageId] = Json.valueReads[HeaderMessageId]
  private implicit val emailAddressReads: Reads[EmailAddress] = Json.reads[EmailAddress]
  private implicit val addressesHeaderValueReads: Reads[AddressesHeaderValue] = Json.valueReads[AddressesHeaderValue]
  private implicit val messageIdsHeaderValueReads: Reads[MessageIdsHeaderValue] = {
    case JsArray(value) => value.map(headerMessageIdReads.reads)
      .map(_.asEither)
      .toList
      .sequence
      .fold(e => JsError(e),
        ids => JsSuccess(MessageIdsHeaderValue(Some(ids).filter(_.nonEmpty))))
    case jsValue => JsError(s"expected JsArray, got $jsValue")
  }

  private implicit val isTruncatedReads: Reads[IsTruncated] = Json.valueReads[IsTruncated]
  private implicit val isEncodingProblemReads: Reads[IsEncodingProblem] = Json.valueReads[IsEncodingProblem]
  private implicit val clientEmailBodyValueReads: Reads[ClientEmailBodyValue] = Json.reads[ClientEmailBodyValue]
  private implicit val typeReads: Reads[Type] = Json.valueReads[Type]
  private implicit val clientPartIdReads: Reads[ClientPartId] = Json.valueReads[ClientPartId]
  private val rawClientBodyReads: Reads[ClientBody] = Json.reads[ClientBody]
  private implicit val clientBodyReads: Reads[ClientBody] = {
    case JsObject(underlying) if underlying.contains("charset") => JsError("charset must not be specified in htmlBody")
    case JsObject(underlying) if underlying.contains("size") => JsError("size must not be specified in htmlBody")
    case JsObject(underlying) if underlying.contains("header:Content-Transfer-Encoding") => JsError("Content-Transfer-Encoding must not be specified in htmlBody or textBody")
    case JsObject(underlying) if underlying.keySet.exists(s => s.startsWith("header:Content-Transfer-Encoding:asText")) => JsError("Content-Transfer-Encoding must not be specified in htmlBody or textBody")
    case o: JsObject => rawClientBodyReads.reads(o)
    case _ => JsError("Expecting a JsObject to represent an ClientHtmlBody")
  }

  private implicit val bodyValuesReads: Reads[Map[ClientPartId, ClientEmailBodyValue]] =
    Reads.mapReads[ClientPartId, ClientEmailBodyValue] {
      s => Id.validate(s).fold(
        e => JsError(e.getMessage),
        partId => JsSuccess(ClientPartId(partId)))
    }

  case class EmailCreationRequestWithoutHeaders(mailboxIds: MailboxIds,
                                                messageId: Option[MessageIdsHeaderValue],
                                                references: Option[MessageIdsHeaderValue],
                                                inReplyTo: Option[MessageIdsHeaderValue],
                                                from: Option[AddressesHeaderValue],
                                                to: Option[AddressesHeaderValue],
                                                cc: Option[AddressesHeaderValue],
                                                bcc: Option[AddressesHeaderValue],
                                                sender: Option[AddressesHeaderValue],
                                                replyTo: Option[AddressesHeaderValue],
                                                subject: Option[Subject],
                                                sentAt: Option[UTCDate],
                                                keywords: Option[Keywords],
                                                receivedAt: Option[UTCDate],
                                                htmlBody: Option[List[ClientBody]],
                                                textBody: Option[List[ClientBody]],
                                                bodyValues: Option[Map[ClientPartId, ClientEmailBodyValue]],
                                                attachments: Option[List[Attachment]]) {
    def toCreationRequest(specificHeaders: List[EmailHeader]): EmailCreationRequest = EmailCreationRequest(
      mailboxIds = mailboxIds,
      messageId = messageId,
      references = references,
      inReplyTo = inReplyTo,
      from = from,
      to = to,
      cc = cc,
      bcc = bcc,
      sender = sender,
      replyTo = replyTo,
      subject = subject,
      sentAt = sentAt,
      keywords = keywords,
      receivedAt = receivedAt,
      specificHeaders = specificHeaders,
      bodyValues = bodyValues,
      htmlBody = htmlBody,
      textBody = textBody,
      attachments = attachments)
  }

  private implicit val headerUrlReads: Reads[HeaderURL] = Json.valueReads[HeaderURL]
  private implicit val groupNameReads: Reads[GroupName] = Json.valueReads[GroupName]
  private implicit val groupReads: Reads[EmailAddressGroup] = Json.reads[EmailAddressGroup]

  private implicit val dateReads: Reads[DateHeaderValue] = {
    case JsNull => JsSuccess(DateHeaderValue(None))
    case json: JsValue => UTCDateReads.reads(json).map(date => DateHeaderValue(Some(date)))
  }

  sealed trait HeaderValueReads extends Reads[EmailHeaderValue]
  case object RawReads extends HeaderValueReads {
    val rawReads: Reads[RawHeaderValue] = Json.valueReads[RawHeaderValue]
    override def reads(json: JsValue): JsResult[EmailHeaderValue] = rawReads.reads(json)
  }
  case object AllReads extends HeaderValueReads {
    val rawReads: Reads[RawHeaderValue] = Json.valueReads[RawHeaderValue]
    override def reads(json: JsValue): JsResult[EmailHeaderValue] = rawReads.reads(json)
  }
  case object TextReads extends HeaderValueReads {
    val textReads: Reads[TextHeaderValue] = Json.valueReads[TextHeaderValue]
    override def reads(json: JsValue): JsResult[TextHeaderValue] = textReads.reads(json)
  }
  case object AddressesReads extends HeaderValueReads {
    override def reads(json: JsValue): JsResult[AddressesHeaderValue] = addressesHeaderValueReads.reads(json)
  }
  case object DateReads extends HeaderValueReads {
    override def reads(json: JsValue): JsResult[DateHeaderValue] = dateReads.reads(json)
  }
  case object MessageIdReads extends HeaderValueReads {
    override def reads(json: JsValue): JsResult[MessageIdsHeaderValue] = messageIdsHeaderValueReads.reads(json)
  }
  case object URLReads extends HeaderValueReads {
    val urlsReads: Reads[URLsHeaderValue] = {