diff options
author | Jakob Odersky <jakob@odersky.com> | 2018-02-14 15:00:52 -0800 |
---|---|---|
committer | Jakob Odersky <jakob@odersky.com> | 2018-02-14 15:00:52 -0800 |
commit | 7ab0889d7ab4480d0d90346432006ffd345b4916 (patch) | |
tree | fccce4902dfc4241a651dfac32e4ef77288de3c9 /src | |
parent | 5a37bfee89a2b5ae17c7980327a92c381c006cf7 (diff) | |
download | spray-json-derivation-7ab0889d7ab4480d0d90346432006ffd345b4916.tar.gz spray-json-derivation-7ab0889d7ab4480d0d90346432006ffd345b4916.tar.bz2 spray-json-derivation-7ab0889d7ab4480d0d90346432006ffd345b4916.zip |
Remove need for special case for enums
Diffstat (limited to 'src')
-rw-r--r-- | src/main/scala/DerivedFormats.scala | 86 | ||||
-rw-r--r-- | src/main/scala/annotations.scala | 9 | ||||
-rw-r--r-- | src/test/scala/CoproductTypeFormats.scala | 9 |
3 files changed, 38 insertions, 66 deletions
diff --git a/src/main/scala/DerivedFormats.scala b/src/main/scala/DerivedFormats.scala index 08c452c..4fc096e 100644 --- a/src/main/scala/DerivedFormats.scala +++ b/src/main/scala/DerivedFormats.scala @@ -27,7 +27,7 @@ trait DerivedFormats { self: BasicFormats => ctx.construct { param => param.typeclass.read(obj.fields(param.label)) } - case str: JsString if ctx.isObject && str.value == ctx.typeName.short => + case JsString(str) if ctx.isObject && str == ctx.typeName.short => ctx.rawConstruct(Seq.empty) case js => @@ -36,64 +36,46 @@ trait DerivedFormats { self: BasicFormats => } } - def dispatch[T](ctx: SealedTrait[JsonFormat, T]): JsonFormat[T] = - new JsonFormat[T] { - def tpe = - ctx.annotations - .find(_.isInstanceOf[JsonAnnotation]) - .getOrElse(new gadt("type")) - - override def write(value: T): JsValue = tpe match { - case _: enum => - ctx.dispatch(value) { sub => - JsString(sub.typeName.short) - } + def dispatch[T](ctx: SealedTrait[JsonFormat, T]): JsonFormat[T] = { + val typeFieldName = ctx.annotations + .collectFirst{ + case g: gadt => g.typeFieldName + } + .getOrElse("type") - case g: gadt => - ctx.dispatch(value) { sub => - val obj = sub.typeclass.write(sub.cast(value)).asJsObject + new JsonFormat[T] { + override def write(value: T): JsValue = ctx.dispatch(value) { sub => + sub.typeclass.write(sub.cast(value)) match { + case obj: JsObject => JsObject( - (Map(g.typeFieldName -> JsString(sub.typeName.short)) ++ + (Map(typeFieldName -> JsString(sub.typeName.short)) ++ obj.fields).toSeq: _*) - } + case js => js + } } - override def read(value: JsValue): T = tpe match { - case _: enum => - value match { - case str: JsString => - ctx.subtypes - .find(_.typeName.short == str.value) - .getOrElse(deserializationError( - s"Cannot deserialize JSON to ${ctx.typeName.full} because " + - "type '${str}' has an unsupported value.")) - .typeclass - .read(str) - case js => - deserializationError( - s"Cannot read JSON '$js' as a ${ctx.typeName.full}") - } - - case g: gadt => - value match { - case obj: JsObject if obj.fields.contains(g.typeFieldName) => - val fieldName = obj.fields(g.typeFieldName).convertTo[String] - - ctx.subtypes.find(_.typeName.short == fieldName) match { - case Some(tpe) => tpe.typeclass.read(obj) - case None => - deserializationError( - s"Cannot deserialize JSON to ${ctx.typeName.full} " + - s"because type field '${fieldName}' has an unsupported " + - "value.") - } + override def read(js: JsValue): T = { + val typeName: String = js match { + case obj: JsObject if obj.fields.contains(typeFieldName) => + obj.fields(typeFieldName).convertTo[String] + case JsString(str) => + str + case _ => + deserializationError( + s"Cannot deserialize JSON to ${ctx.typeName.full} " + + "because serialized type cannot be determined.") + } - case js => - deserializationError( - s"Cannot read JSON '$js' as a ${ctx.typeName}") - } + ctx.subtypes.find(_.typeName.short == typeName) match { + case Some(tpe) => tpe.typeclass.read(js) + case None => + deserializationError( + s"Cannot deserialize JSON to ${ctx.typeName.full} " + + s"because type '${typeName}' is unsupported.") + } } - } + } + } implicit def gen[T]: JsonFormat[T] = macro Magnolia.gen[T] diff --git a/src/main/scala/annotations.scala b/src/main/scala/annotations.scala index f23fbcb..ee179ff 100644 --- a/src/main/scala/annotations.scala +++ b/src/main/scala/annotations.scala @@ -2,9 +2,6 @@ package xyz.driver.json import scala.annotation.StaticAnnotation -/** Indicator trait of anontations related to JSON formatting. */ -sealed trait JsonAnnotation - /** An annotation that designates that a sealed trait is a generalized algebraic * datatype (GADT), and that a type field containing the serialized childrens' * types should be added to the final JSON objects. @@ -25,9 +22,3 @@ sealed trait JsonAnnotation * object */ final class gadt(val typeFieldName: String = "type") extends StaticAnnotation - with JsonAnnotation - -/** An annotation that designates that a sealed trait is an enumeration (all - * children are strictly case objects), and that all children should be - * serialized as strings. */ -final class enum extends StaticAnnotation with JsonAnnotation diff --git a/src/test/scala/CoproductTypeFormats.scala b/src/test/scala/CoproductTypeFormats.scala index f16e4c7..f9b71b8 100644 --- a/src/test/scala/CoproductTypeFormats.scala +++ b/src/test/scala/CoproductTypeFormats.scala @@ -31,10 +31,10 @@ class CoproductTypeFormats """{"type":"Plus","lhs":{"type":"Value","x":42},"rhs":{"type":"Value","x":0}}""" ) - // "Case object child" should behave like checkCoherence[Expr]( - // One, - // """{"type":"One"}""" - // ) + "Case object child" should behave like checkCoherence[Expr]( + One, + """"One"""" + ) @gadt("kind") sealed abstract class Keyword(`type`: String) @@ -45,7 +45,6 @@ class CoproductTypeFormats """{"kind":"If","type":"class"}""" ) - @enum sealed trait Enum case object A extends Enum case object B extends Enum |