You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by rc...@apache.org on 2020/06/08 03:12:36 UTC

[james-project] 15/16: JAMES-3171 JsError serialization

This is an automated email from the ASF dual-hosted git repository.

rcordier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit eef1f7e92565d37d2be2fe853802f276d7530d69
Author: Rene Cordier <rc...@linagora.com>
AuthorDate: Fri May 29 11:38:30 2020 +0700

    JAMES-3171 JsError serialization
---
 .../org/apache/james/jmap/json/Serializer.scala    | 64 +++++++++++----------
 .../james/jmap/method/MailboxGetMethod.scala       |  2 +-
 .../james/jmap/json/JsErrorSerializationTest.scala | 66 ++++++++++++++++++++++
 3 files changed, 100 insertions(+), 32 deletions(-)

diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/Serializer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/Serializer.scala
index 6d374ed..76c6863 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/Serializer.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/Serializer.scala
@@ -34,6 +34,7 @@ import org.apache.james.mailbox.model.{MailboxACL, MailboxId}
 import play.api.libs.functional.syntax._
 import play.api.libs.json._
 
+import scala.collection.{Seq => LegacySeq}
 import scala.util.Try
 
 class Serializer @Inject() (mailboxIdFactory: MailboxId.Factory) {
@@ -158,7 +159,7 @@ class Serializer @Inject() (mailboxIdFactory: MailboxId.Factory) {
   private implicit val mailboxRightsWrites: Writes[MailboxRights] = Json.writes[MailboxRights]
 
   private implicit val mailboxNamespaceWrites: Writes[MailboxNamespace] = {
-    case personal: PersonalNamespace => JsString("Personal")
+    case _: PersonalNamespace => JsString("Personal")
     case delegated: DelegatedNamespace => JsString(s"Delegated[${delegated.owner.asString}]")
   }
 
@@ -209,43 +210,44 @@ class Serializer @Inject() (mailboxIdFactory: MailboxId.Factory) {
   private implicit val notFoundWrites: Writes[NotFound] = Json.valueWrites[NotFound]
   private implicit val mailboxGetResponseWrites: Writes[MailboxGetResponse] = Json.writes[MailboxGetResponse]
 
-  def serialize(session: Session): JsValue = {
-    Json.toJson(session)
-  }
+  private implicit val jsonValidationErrorWrites: Writes[JsonValidationError] = error => JsString(error.message)
 
-  def serialize(requestObject: RequestObject): JsValue = {
-    Json.toJson(requestObject)
-  }
+  private implicit def jsonValidationErrorsWrites(implicit jsonValidationErrorWrites: Writes[JsonValidationError]): Writes[LegacySeq[JsonValidationError]] =
+    (errors: LegacySeq[JsonValidationError]) => {
+      JsArray(errors.map(error => jsonValidationErrorWrites.writes(error)).toArray[JsValue])
+    }
 
-  def serialize(responseObject: ResponseObject): JsValue = {
-    Json.toJson(responseObject)
-  }
+  private implicit def errorsWrites(implicit jsonValidationErrorsWrites: Writes[LegacySeq[JsonValidationError]]): Writes[LegacySeq[(JsPath, LegacySeq[JsonValidationError])]] =
+    (errors: LegacySeq[(JsPath, LegacySeq[JsonValidationError])]) => {
+      errors.foldLeft(JsArray.empty)((jsArray, jsError) => {
+        val (path: JsPath, list: LegacySeq[JsonValidationError]) = jsError
+        jsArray:+ JsObject(Seq(
+          "path" -> JsString(path.toJsonString),
+          "messages" -> jsonValidationErrorsWrites.writes(list)))
+      })
+    }
 
-  def serialize(mailbox: Mailbox): JsValue = {
-    Json.toJson(mailbox)
-  }
+  private implicit def jsErrorWrites: Writes[JsError] = Json.writes[JsError]
 
-  def serialize(mailboxGetResponse: MailboxGetResponse): JsValue = {
-    Json.toJson(mailboxGetResponse)
-  }
+  def serialize(session: Session): JsValue = Json.toJson(session)
 
-  def deserializeRequestObject(input: String): JsResult[RequestObject] = {
-    Json.parse(input).validate[RequestObject]
-  }
+  def serialize(requestObject: RequestObject): JsValue = Json.toJson(requestObject)
 
-  def deserializeRequestObject(input: InputStream): JsResult[RequestObject] = {
-    Json.parse(input).validate[RequestObject]
-  }
+  def serialize(responseObject: ResponseObject): JsValue = Json.toJson(responseObject)
 
-  def deserializeResponseObject(input: String): JsResult[ResponseObject] = {
-    Json.parse(input).validate[ResponseObject]
-  }
+  def serialize(mailbox: Mailbox): JsValue = Json.toJson(mailbox)
 
-  def deserializeMailboxGetRequest(input: String): JsResult[MailboxGetRequest] = {
-    Json.parse(input).validate[MailboxGetRequest]
-  }
+  def serialize(mailboxGetResponse: MailboxGetResponse): JsValue = Json.toJson(mailboxGetResponse)
 
-  def deserializeMailboxGetRequest(input: JsValue): JsResult[MailboxGetRequest] = {
-    Json.fromJson[MailboxGetRequest](input)
-  }
+  def serialize(errors: JsError): JsValue = Json.toJson(errors)
+
+  def deserializeRequestObject(input: String): JsResult[RequestObject] = Json.parse(input).validate[RequestObject]
+
+  def deserializeRequestObject(input: InputStream): JsResult[RequestObject] = Json.parse(input).validate[RequestObject]
+
+  def deserializeResponseObject(input: String): JsResult[ResponseObject] = Json.parse(input).validate[ResponseObject]
+
+  def deserializeMailboxGetRequest(input: String): JsResult[MailboxGetRequest] = Json.parse(input).validate[MailboxGetRequest]
+
+  def deserializeMailboxGetRequest(input: JsValue): JsResult[MailboxGetRequest] = Json.fromJson[MailboxGetRequest](input)
 }
\ No newline at end of file
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxGetMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxGetMethod.scala
index 1ccb921..22c38c6 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxGetMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxGetMethod.scala
@@ -63,7 +63,7 @@ class MailboxGetMethod @Inject() (serializer: Serializer,
   private def asMailboxGetRequest(arguments: Arguments): SMono[MailboxGetRequest] = {
     serializer.deserializeMailboxGetRequest(arguments.value) match {
       case JsSuccess(mailboxGetRequest, _) => SMono.just(mailboxGetRequest)
-      case JsError(errors) => SMono.raiseError(new IllegalArgumentException("Invalid MailboxGetRequest")) //FIXME MOB
+      case errors: JsError => SMono.raiseError(new IllegalArgumentException(serializer.serialize(errors).toString))
     }
   }
 
diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/JsErrorSerializationTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/JsErrorSerializationTest.scala
new file mode 100644
index 0000000..cd980aa
--- /dev/null
+++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/JsErrorSerializationTest.scala
@@ -0,0 +1,66 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.jmap.json
+
+import net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson
+import org.apache.james.mailbox.model.TestId
+import org.scalatest.matchers.should.Matchers
+import org.scalatest.wordspec.AnyWordSpec
+import play.api.libs.json.{JsError, JsPath, Json, JsonValidationError}
+
+object JsErrorSerializationTest {
+  private val SERIALIZER: Serializer = new Serializer(new TestId.Factory)
+}
+
+class JsErrorSerializationTest extends AnyWordSpec with Matchers {
+  import JsErrorSerializationTest.SERIALIZER
+
+  "Serialize JsError" should {
+    "succeed " in {
+      val errors: JsError = JsError(Seq(
+        (
+          JsPath.\("name"),
+          Seq(JsonValidationError("validate.error.expected.jsstring"), JsonValidationError("error.maxLength"))
+        ),
+        (
+          JsPath.\("id"),
+          Seq(JsonValidationError("error.path.missing"))
+        )))
+
+      val expectedJson: String =
+        """
+          |{
+          |  "errors": [
+          |    {
+          |      "path": "obj.name",
+          |      "messages": ["validate.error.expected.jsstring", "error.maxLength"]
+          |    },
+          |    {
+          |      "path": "obj.id",
+          |      "messages": ["error.path.missing"]
+          |    }
+          |  ]
+          |}
+          |""".stripMargin
+
+      assertThatJson(Json.stringify(SERIALIZER.serialize(errors))).isEqualTo(expectedJson)
+    }
+  }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org