From e06de2f52108810790349caa8b4fde0cb91517e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Chantepie?= Date: Fri, 19 Jun 2026 15:15:59 +0200 Subject: [PATCH 1/5] test(elastic4play): First add unit test on existing Elastic4Play Json format (without implementation change) --- .../app/org/elastic4play/JsonFormat.scala | 16 +++-- .../org/elastic4play/JsonFormatSpec.scala | 59 +++++++++++++++++++ 2 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 elastic4play/test/org/elastic4play/JsonFormatSpec.scala diff --git a/elastic4play/app/org/elastic4play/JsonFormat.scala b/elastic4play/app/org/elastic4play/JsonFormat.scala index fe64d8230..deb245c66 100644 --- a/elastic4play/app/org/elastic4play/JsonFormat.scala +++ b/elastic4play/app/org/elastic4play/JsonFormat.scala @@ -14,22 +14,30 @@ object JsonFormat { private val dateWrites: Writes[Date] = Writes[Date](d => JsNumber(d.getTime)) implicit val dateFormat: Format[Date] = Format(dateReads, dateWrites) - private val invalidFormatAttributeErrorWrites = Writes[InvalidFormatAttributeError] { ifae => + private def attributeErrorWrites[E <: AttributeError](underlying: OWrites[E])(tpe: String): OWrites[E] = { + val discriminator: (String, JsValue) = "type" -> JsString(tpe) + + OWrites.transform(underlying) { (origErr, obj) => + obj + discriminator + ("message" -> JsString(origErr.toString)) + } + } + + private[elastic4play] val invalidFormatAttributeErrorWrites = OWrites[InvalidFormatAttributeError] { ifae => Json.writes[InvalidFormatAttributeError].writes(ifae) + ("type" -> JsString("InvalidFormatAttributeError")) + ("message" -> JsString(ifae.toString)) } - private val unknownAttributeErrorWrites = Writes[UnknownAttributeError] { uae => + private[elastic4play] val unknownAttributeErrorWrites = OWrites[UnknownAttributeError] { uae => Json.writes[UnknownAttributeError].writes(uae) + ("type" -> JsString("UnknownAttributeError")) + ("message" -> JsString(uae.toString)) } - private val updateReadOnlyAttributeErrorWrites = Writes[UpdateReadOnlyAttributeError] { uroae => + private[elastic4play] val updateReadOnlyAttributeErrorWrites = OWrites[UpdateReadOnlyAttributeError] { uroae => Json.writes[UpdateReadOnlyAttributeError].writes(uroae) + ("type" -> JsString("UpdateReadOnlyAttributeError")) + ("message" -> JsString(uroae.toString)) } - private val missingAttributeErrorWrites = Writes[MissingAttributeError] { mae => + private[elastic4play] val missingAttributeErrorWrites = OWrites[MissingAttributeError] { mae => Json.writes[MissingAttributeError].writes(mae) + ("type" -> JsString("MissingAttributeError")) + ("message" -> JsString(mae.toString)) diff --git a/elastic4play/test/org/elastic4play/JsonFormatSpec.scala b/elastic4play/test/org/elastic4play/JsonFormatSpec.scala new file mode 100644 index 000000000..2c0044f39 --- /dev/null +++ b/elastic4play/test/org/elastic4play/JsonFormatSpec.scala @@ -0,0 +1,59 @@ +package org.elastic4play + +import play.api.libs.json._ + +import org.elastic4play.controllers.JsonInputValue + +final class JsonFormatSpec extends org.specs2.mutable.Specification { + "Play JSON format for Elastic".title + + "Format for attribute errors" should { + "support InvalidFormatAttributeError" in { + implicit def w: OWrites[InvalidFormatAttributeError] = + JsonFormat.invalidFormatAttributeErrorWrites + + Json.toJsObject(InvalidFormatAttributeError( + name = "Test 1", + format = "Foo", + value = JsonInputValue(JsString("Input")))) must_=== Json.obj( + "name" -> "Test 1", + "format" -> "Foo", + "value" -> Json.obj("type" -> "JsonInputValue", "value" -> "Input"), + "type" -> "InvalidFormatAttributeError", + "message" -> "Invalid format for Test 1: JsonInputValue(\"Input\"), expected Foo") + } + + "support UnknownAttributeError" in { + implicit def w: OWrites[UnknownAttributeError] = + JsonFormat.unknownAttributeErrorWrites + + Json.toJsObject(UnknownAttributeError( + name = "Test 2", + value = JsString("Bar"))) must_=== Json.obj( + "name" -> "Test 2", + "value" -> "Bar", + "type" -> "UnknownAttributeError", + "message" -> "Unknown attribute Test 2: \"Bar\"") + } + + "support UpdateReadOnlyAttributeError" in { + implicit def w: OWrites[UpdateReadOnlyAttributeError] = + JsonFormat.updateReadOnlyAttributeErrorWrites + + Json.toJsObject(UpdateReadOnlyAttributeError("Lorem")) must_=== Json.obj( + "name" -> "Lorem", + "type" -> "UpdateReadOnlyAttributeError", + "message" -> "Attribute Lorem is read-only") + } + + "support MissingAttributeError" in { + implicit def w: OWrites[MissingAttributeError] = + JsonFormat.missingAttributeErrorWrites + + Json.toJsObject(MissingAttributeError("Ipsum")) must_=== Json.obj( + "name" -> "Ipsum", + "type" -> "MissingAttributeError", + "message" -> "Attribute Ipsum is missing") + } + } +} From aea1aa2e9d29bc3194d9a5b790c8a736f11cc355 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Chantepie?= Date: Fri, 19 Jun 2026 15:19:20 +0200 Subject: [PATCH 2/5] chore(elastic4play): Refactor Elastic4Play JSON format; Introduce common function `attributeErrorWrites`: - Enforce format consistency between the different error kinds (for the `type` discriminator and `message` fields). - Avoid calling macro materialization (micro-optimization) on each writes call (`OWrite[..] { Json.writes[..]/* !! */.writes(..) ... }`). --- .../app/org/elastic4play/JsonFormat.scala | 29 +++++-------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/elastic4play/app/org/elastic4play/JsonFormat.scala b/elastic4play/app/org/elastic4play/JsonFormat.scala index deb245c66..655192eb0 100644 --- a/elastic4play/app/org/elastic4play/JsonFormat.scala +++ b/elastic4play/app/org/elastic4play/JsonFormat.scala @@ -14,7 +14,7 @@ object JsonFormat { private val dateWrites: Writes[Date] = Writes[Date](d => JsNumber(d.getTime)) implicit val dateFormat: Format[Date] = Format(dateReads, dateWrites) - private def attributeErrorWrites[E <: AttributeError](underlying: OWrites[E])(tpe: String): OWrites[E] = { + private def attributeErrorWrites[E <: AttributeError](underlying: OWrites[E], tpe: String): OWrites[E] = { val discriminator: (String, JsValue) = "type" -> JsString(tpe) OWrites.transform(underlying) { (origErr, obj) => @@ -22,26 +22,13 @@ object JsonFormat { } } - private[elastic4play] val invalidFormatAttributeErrorWrites = OWrites[InvalidFormatAttributeError] { ifae => - Json.writes[InvalidFormatAttributeError].writes(ifae) + - ("type" -> JsString("InvalidFormatAttributeError")) + - ("message" -> JsString(ifae.toString)) - } - private[elastic4play] val unknownAttributeErrorWrites = OWrites[UnknownAttributeError] { uae => - Json.writes[UnknownAttributeError].writes(uae) + - ("type" -> JsString("UnknownAttributeError")) + - ("message" -> JsString(uae.toString)) - } - private[elastic4play] val updateReadOnlyAttributeErrorWrites = OWrites[UpdateReadOnlyAttributeError] { uroae => - Json.writes[UpdateReadOnlyAttributeError].writes(uroae) + - ("type" -> JsString("UpdateReadOnlyAttributeError")) + - ("message" -> JsString(uroae.toString)) - } - private[elastic4play] val missingAttributeErrorWrites = OWrites[MissingAttributeError] { mae => - Json.writes[MissingAttributeError].writes(mae) + - ("type" -> JsString("MissingAttributeError")) + - ("message" -> JsString(mae.toString)) - } + private[elastic4play] val invalidFormatAttributeErrorWrites: OWrites[InvalidFormatAttributeError] = attributeErrorWrites[InvalidFormatAttributeError](Json.writes[InvalidFormatAttributeError], "InvalidFormatAttributeError") + + private[elastic4play] val unknownAttributeErrorWrites: OWrites[UnknownAttributeError] = attributeErrorWrites[UnknownAttributeError](Json.writes[UnknownAttributeError], "UnknownAttributeError") + + private[elastic4play] val updateReadOnlyAttributeErrorWrites: OWrites[UpdateReadOnlyAttributeError] = attributeErrorWrites[UpdateReadOnlyAttributeError](Json.writes[UpdateReadOnlyAttributeError], "UpdateReadOnlyAttributeError") + + private[elastic4play] val missingAttributeErrorWrites: OWrites[MissingAttributeError] = attributeErrorWrites(Json.writes[MissingAttributeError], "MissingAttributeError") implicit val attributeCheckingExceptionWrites: OWrites[AttributeCheckingError] = OWrites[AttributeCheckingError] { ace => Json.obj( From 905b83df2e13379aa6bc38f4103e2020e2a8524d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Chantepie?= Date: Fri, 19 Jun 2026 15:27:35 +0200 Subject: [PATCH 3/5] chore(elastic4play): Automatic discriminator in JSON format for attribute error --- elastic4play/app/org/elastic4play/JsonFormat.scala | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/elastic4play/app/org/elastic4play/JsonFormat.scala b/elastic4play/app/org/elastic4play/JsonFormat.scala index 655192eb0..d5a006381 100644 --- a/elastic4play/app/org/elastic4play/JsonFormat.scala +++ b/elastic4play/app/org/elastic4play/JsonFormat.scala @@ -4,6 +4,8 @@ import java.util.Date import scala.util.{Failure, Success, Try} +import scala.reflect.ClassTag + import play.api.libs.json._ import org.elastic4play.controllers.JsonFormat.inputValueFormat @@ -14,21 +16,21 @@ object JsonFormat { private val dateWrites: Writes[Date] = Writes[Date](d => JsNumber(d.getTime)) implicit val dateFormat: Format[Date] = Format(dateReads, dateWrites) - private def attributeErrorWrites[E <: AttributeError](underlying: OWrites[E], tpe: String): OWrites[E] = { - val discriminator: (String, JsValue) = "type" -> JsString(tpe) + private def attributeErrorWrites[E <: AttributeError](underlying: OWrites[E])(implicit cls: ClassTag[E]): OWrites[E] = { + val discriminator: (String, JsValue) = "type" -> JsString(cls.runtimeClass.getSimpleName) OWrites.transform(underlying) { (origErr, obj) => obj + discriminator + ("message" -> JsString(origErr.toString)) } } - private[elastic4play] val invalidFormatAttributeErrorWrites: OWrites[InvalidFormatAttributeError] = attributeErrorWrites[InvalidFormatAttributeError](Json.writes[InvalidFormatAttributeError], "InvalidFormatAttributeError") + private[elastic4play] val invalidFormatAttributeErrorWrites: OWrites[InvalidFormatAttributeError] = attributeErrorWrites[InvalidFormatAttributeError](Json.writes[InvalidFormatAttributeError]) - private[elastic4play] val unknownAttributeErrorWrites: OWrites[UnknownAttributeError] = attributeErrorWrites[UnknownAttributeError](Json.writes[UnknownAttributeError], "UnknownAttributeError") + private[elastic4play] val unknownAttributeErrorWrites: OWrites[UnknownAttributeError] = attributeErrorWrites[UnknownAttributeError](Json.writes[UnknownAttributeError]) - private[elastic4play] val updateReadOnlyAttributeErrorWrites: OWrites[UpdateReadOnlyAttributeError] = attributeErrorWrites[UpdateReadOnlyAttributeError](Json.writes[UpdateReadOnlyAttributeError], "UpdateReadOnlyAttributeError") + private[elastic4play] val updateReadOnlyAttributeErrorWrites: OWrites[UpdateReadOnlyAttributeError] = attributeErrorWrites[UpdateReadOnlyAttributeError](Json.writes[UpdateReadOnlyAttributeError]) - private[elastic4play] val missingAttributeErrorWrites: OWrites[MissingAttributeError] = attributeErrorWrites(Json.writes[MissingAttributeError], "MissingAttributeError") + private[elastic4play] val missingAttributeErrorWrites: OWrites[MissingAttributeError] = attributeErrorWrites(Json.writes[MissingAttributeError]) implicit val attributeCheckingExceptionWrites: OWrites[AttributeCheckingError] = OWrites[AttributeCheckingError] { ace => Json.obj( From 18c7f95beeead321054a49765ee367c87ac1f9af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Chantepie?= Date: Fri, 19 Jun 2026 15:55:14 +0200 Subject: [PATCH 4/5] test(elastic4play): Adding unit test on existing JSON format for AttributeCheckingError (no implementation change on itself) --- .../org/elastic4play/JsonFormatSpec.scala | 87 ++++++++++++++----- 1 file changed, 63 insertions(+), 24 deletions(-) diff --git a/elastic4play/test/org/elastic4play/JsonFormatSpec.scala b/elastic4play/test/org/elastic4play/JsonFormatSpec.scala index 2c0044f39..7da050541 100644 --- a/elastic4play/test/org/elastic4play/JsonFormatSpec.scala +++ b/elastic4play/test/org/elastic4play/JsonFormatSpec.scala @@ -8,52 +8,91 @@ final class JsonFormatSpec extends org.specs2.mutable.Specification { "Play JSON format for Elastic".title "Format for attribute errors" should { + val invalidFormatAttrErr = InvalidFormatAttributeError( + name = "Test 1", + format = "Foo", + value = JsonInputValue(JsString("Input"))) + + val invalidFormatAttrErrJson = Json.obj( + "name" -> "Test 1", + "format" -> "Foo", + "value" -> Json.obj("type" -> "JsonInputValue", "value" -> "Input"), + "type" -> "InvalidFormatAttributeError", + "message" -> "Invalid format for Test 1: JsonInputValue(\"Input\"), expected Foo") + "support InvalidFormatAttributeError" in { implicit def w: OWrites[InvalidFormatAttributeError] = JsonFormat.invalidFormatAttributeErrorWrites - Json.toJsObject(InvalidFormatAttributeError( - name = "Test 1", - format = "Foo", - value = JsonInputValue(JsString("Input")))) must_=== Json.obj( - "name" -> "Test 1", - "format" -> "Foo", - "value" -> Json.obj("type" -> "JsonInputValue", "value" -> "Input"), - "type" -> "InvalidFormatAttributeError", - "message" -> "Invalid format for Test 1: JsonInputValue(\"Input\"), expected Foo") + Json.toJsObject(invalidFormatAttrErr) must_=== invalidFormatAttrErrJson } + val unknownAttrErr = UnknownAttributeError( + name = "Test 2", + value = JsString("Bar")) + + val unknownAttrErrJson = Json.obj( + "name" -> "Test 2", + "value" -> "Bar", + "type" -> "UnknownAttributeError", + "message" -> "Unknown attribute Test 2: \"Bar\"") + "support UnknownAttributeError" in { implicit def w: OWrites[UnknownAttributeError] = JsonFormat.unknownAttributeErrorWrites - Json.toJsObject(UnknownAttributeError( - name = "Test 2", - value = JsString("Bar"))) must_=== Json.obj( - "name" -> "Test 2", - "value" -> "Bar", - "type" -> "UnknownAttributeError", - "message" -> "Unknown attribute Test 2: \"Bar\"") + Json.toJsObject(unknownAttrErr) must_=== unknownAttrErrJson } + val updateRoAttrErr = UpdateReadOnlyAttributeError("Lorem") + + val updateRoAttrErrJson = Json.obj( + "name" -> "Lorem", + "type" -> "UpdateReadOnlyAttributeError", + "message" -> "Attribute Lorem is read-only") + "support UpdateReadOnlyAttributeError" in { implicit def w: OWrites[UpdateReadOnlyAttributeError] = JsonFormat.updateReadOnlyAttributeErrorWrites - Json.toJsObject(UpdateReadOnlyAttributeError("Lorem")) must_=== Json.obj( - "name" -> "Lorem", - "type" -> "UpdateReadOnlyAttributeError", - "message" -> "Attribute Lorem is read-only") + Json.toJsObject(updateRoAttrErr) must_=== updateRoAttrErrJson } + val missingAttrErr = MissingAttributeError("Ipsum") + + val missingAttrErrJson = Json.obj( + "name" -> "Ipsum", + "type" -> "MissingAttributeError", + "message" -> "Attribute Ipsum is missing") + "support MissingAttributeError" in { implicit def w: OWrites[MissingAttributeError] = JsonFormat.missingAttributeErrorWrites - Json.toJsObject(MissingAttributeError("Ipsum")) must_=== Json.obj( - "name" -> "Ipsum", - "type" -> "MissingAttributeError", - "message" -> "Attribute Ipsum is missing") + Json.toJsObject(missingAttrErr) must_=== missingAttrErrJson + } + + "support AttributeCheckingError" in { + import JsonFormat.attributeCheckingExceptionWrites + + val errors = Seq(invalidFormatAttrErr, unknownAttrErr, updateRoAttrErr, missingAttrErr) + + val errorsJson = Seq(invalidFormatAttrErrJson, unknownAttrErrJson, updateRoAttrErrJson, missingAttrErrJson) + + Json.toJsObject(AttributeCheckingError( + tableName = "Table 1", + errors = errors)) must_=== Json.obj( + "tableName" -> "Table 1", + "type" -> "AttributeCheckingError", + "errors" -> errorsJson) and { + // Reverse errors to make sure the order is preserved + Json.toJsObject(AttributeCheckingError( + tableName = "Table 2", + errors = errors.reverse)) must_=== Json.obj( + "tableName" -> "Table 2", + "type" -> "AttributeCheckingError", + "errors" -> errorsJson.reverse) + } } } } From d2bcdce81b2ce0f2c23dc5bb3a65bb84390a7cd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Chantepie?= Date: Fri, 19 Jun 2026 16:23:06 +0200 Subject: [PATCH 5/5] core(elastic4play): Refactor JSON format for Elastic4Play AttributeCheckingError: - Remove 'manual' discriminator from individual writes - Use Play JSON capability to automatically derive `OWrites` for sealed trait - Make sure the macro is configured with custom discriminator (field & value) --- .../app/org/elastic4play/JsonFormat.scala | 36 +++++++++---------- .../org/elastic4play/JsonFormatSpec.scala | 10 +++--- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/elastic4play/app/org/elastic4play/JsonFormat.scala b/elastic4play/app/org/elastic4play/JsonFormat.scala index d5a006381..885a2939a 100644 --- a/elastic4play/app/org/elastic4play/JsonFormat.scala +++ b/elastic4play/app/org/elastic4play/JsonFormat.scala @@ -16,33 +16,31 @@ object JsonFormat { private val dateWrites: Writes[Date] = Writes[Date](d => JsNumber(d.getTime)) implicit val dateFormat: Format[Date] = Format(dateReads, dateWrites) - private def attributeErrorWrites[E <: AttributeError](underlying: OWrites[E])(implicit cls: ClassTag[E]): OWrites[E] = { - val discriminator: (String, JsValue) = "type" -> JsString(cls.runtimeClass.getSimpleName) - + private def attributeErrorWrites[E <: AttributeError](underlying: OWrites[E]): OWrites[E] = { OWrites.transform(underlying) { (origErr, obj) => - obj + discriminator + ("message" -> JsString(origErr.toString)) + obj + ("message" -> JsString(origErr.toString)) } } - private[elastic4play] val invalidFormatAttributeErrorWrites: OWrites[InvalidFormatAttributeError] = attributeErrorWrites[InvalidFormatAttributeError](Json.writes[InvalidFormatAttributeError]) + private[elastic4play] implicit val invalidFormatAttributeErrorWrites: OWrites[InvalidFormatAttributeError] = attributeErrorWrites[InvalidFormatAttributeError](Json.writes[InvalidFormatAttributeError]) + + private[elastic4play] implicit val unknownAttributeErrorWrites: OWrites[UnknownAttributeError] = attributeErrorWrites[UnknownAttributeError](Json.writes[UnknownAttributeError]) + + private[elastic4play] implicit val updateReadOnlyAttributeErrorWrites: OWrites[UpdateReadOnlyAttributeError] = attributeErrorWrites[UpdateReadOnlyAttributeError](Json.writes[UpdateReadOnlyAttributeError]) + + private[elastic4play] implicit val missingAttributeErrorWrites: OWrites[MissingAttributeError] = attributeErrorWrites(Json.writes[MissingAttributeError]) - private[elastic4play] val unknownAttributeErrorWrites: OWrites[UnknownAttributeError] = attributeErrorWrites[UnknownAttributeError](Json.writes[UnknownAttributeError]) + implicit val attributeCheckingExceptionWrites: OWrites[AttributeCheckingError] = { + val pkgName = classOf[AttributeError].getPackage.getName + '.' - private[elastic4play] val updateReadOnlyAttributeErrorWrites: OWrites[UpdateReadOnlyAttributeError] = attributeErrorWrites[UpdateReadOnlyAttributeError](Json.writes[UpdateReadOnlyAttributeError]) + implicit def errWrites: OWrites[AttributeError] = Json.configured(JsonConfiguration( + discriminator = "type", + typeNaming = JsonNaming(_.stripPrefix(pkgName)) + )).writes - private[elastic4play] val missingAttributeErrorWrites: OWrites[MissingAttributeError] = attributeErrorWrites(Json.writes[MissingAttributeError]) + val discriminator = "type" -> JsString("AttributeCheckingError") - implicit val attributeCheckingExceptionWrites: OWrites[AttributeCheckingError] = OWrites[AttributeCheckingError] { ace => - Json.obj( - "tableName" -> ace.tableName, - "type" -> "AttributeCheckingError", - "errors" -> JsArray(ace.errors.map { - case e: InvalidFormatAttributeError => invalidFormatAttributeErrorWrites.writes(e) - case e: UnknownAttributeError => unknownAttributeErrorWrites.writes(e) - case e: UpdateReadOnlyAttributeError => updateReadOnlyAttributeErrorWrites.writes(e) - case e: MissingAttributeError => missingAttributeErrorWrites.writes(e) - }) - ) + Json.writes[AttributeCheckingError].transform(_ + discriminator) } implicit def tryWrites[A](implicit aWrites: Writes[A]): Writes[Try[A]] = Writes[Try[A]] { diff --git a/elastic4play/test/org/elastic4play/JsonFormatSpec.scala b/elastic4play/test/org/elastic4play/JsonFormatSpec.scala index 7da050541..498cc0563 100644 --- a/elastic4play/test/org/elastic4play/JsonFormatSpec.scala +++ b/elastic4play/test/org/elastic4play/JsonFormatSpec.scala @@ -17,7 +17,6 @@ final class JsonFormatSpec extends org.specs2.mutable.Specification { "name" -> "Test 1", "format" -> "Foo", "value" -> Json.obj("type" -> "JsonInputValue", "value" -> "Input"), - "type" -> "InvalidFormatAttributeError", "message" -> "Invalid format for Test 1: JsonInputValue(\"Input\"), expected Foo") "support InvalidFormatAttributeError" in { @@ -34,7 +33,6 @@ final class JsonFormatSpec extends org.specs2.mutable.Specification { val unknownAttrErrJson = Json.obj( "name" -> "Test 2", "value" -> "Bar", - "type" -> "UnknownAttributeError", "message" -> "Unknown attribute Test 2: \"Bar\"") "support UnknownAttributeError" in { @@ -48,7 +46,6 @@ final class JsonFormatSpec extends org.specs2.mutable.Specification { val updateRoAttrErrJson = Json.obj( "name" -> "Lorem", - "type" -> "UpdateReadOnlyAttributeError", "message" -> "Attribute Lorem is read-only") "support UpdateReadOnlyAttributeError" in { @@ -62,7 +59,6 @@ final class JsonFormatSpec extends org.specs2.mutable.Specification { val missingAttrErrJson = Json.obj( "name" -> "Ipsum", - "type" -> "MissingAttributeError", "message" -> "Attribute Ipsum is missing") "support MissingAttributeError" in { @@ -77,7 +73,11 @@ final class JsonFormatSpec extends org.specs2.mutable.Specification { val errors = Seq(invalidFormatAttrErr, unknownAttrErr, updateRoAttrErr, missingAttrErr) - val errorsJson = Seq(invalidFormatAttrErrJson, unknownAttrErrJson, updateRoAttrErrJson, missingAttrErrJson) + val errorsJson = Seq( + (invalidFormatAttrErrJson + ("type" -> JsString("InvalidFormatAttributeError"))), + (unknownAttrErrJson + ("type" -> JsString("UnknownAttributeError"))), + (updateRoAttrErrJson + ("type" -> JsString("UpdateReadOnlyAttributeError"))), + (missingAttrErrJson + ("type" -> JsString("MissingAttributeError")))) Json.toJsObject(AttributeCheckingError( tableName = "Table 1",