diff --git a/build.sc b/build.sc index 8a42a474c..e67e8bef1 100644 --- a/build.sc +++ b/build.sc @@ -56,7 +56,9 @@ trait CommonPublishModule "3.1.2", "3.1.3", "3.1.4", -// "3.1.5", Not sure why this fails, maybe some artifacts were not properly published? + "3.2.0", + "3.3.0", + "3.3.1", ) def isDotty = crossScalaVersion.startsWith("0") || crossScalaVersion.startsWith("3") def pomSettings = PomSettings( diff --git a/upickle/core/src/upickle/core/Types.scala b/upickle/core/src/upickle/core/Types.scala index 74beaa53f..9d729eaf6 100644 --- a/upickle/core/src/upickle/core/Types.scala +++ b/upickle/core/src/upickle/core/Types.scala @@ -169,11 +169,15 @@ trait Types{ types => } } object TaggedReader{ - class Leaf[T](private[upickle] override val tagKey: String, tagValue: String, r: Reader[T]) extends TaggedReader[T]{ + class Leaf[T](private[upickle] override val tagKey: String, + tagValue: String, + tagShortValue: String, + r: Reader[T]) extends TaggedReader[T]{ @deprecated("Not used, left for binary compatibility") - def this(tag: String, r: Reader[T]) = this(Annotator.defaultTagKey, tag, r) + def this(tag: String, r: Reader[T]) = this(Annotator.defaultTagKey, tag, tag, r) + def this(tagKey: String, tagValue: String, r: Reader[T]) = this(tagKey, tagValue, tagValue, r) - def findReader(s: String) = if (s == tagValue) r else null + def findReader(s: String) = if (s == tagValue || s == tagShortValue) r else null } class Node[T](private[upickle] override val tagKey: String, rs: TaggedReader[_ <: T]*) extends TaggedReader[T]{ @deprecated("Not used, left for binary compatibility") @@ -201,7 +205,10 @@ trait Types{ types => } } object TaggedWriter{ - class Leaf[T](checker: Annotator.Checker, tagKey: String, tagValue: String, r: ObjectWriter[T]) extends TaggedWriter[T]{ + class Leaf[T](checker: Annotator.Checker, + tagKey: String, + tagValue: String, + r: ObjectWriter[T]) extends TaggedWriter[T]{ @deprecated("Not used, left for binary compatibility") def this(checker: Annotator.Checker, tag: String, r: ObjectWriter[T]) = this(checker, Annotator.defaultTagKey, tag, r) @@ -234,10 +241,12 @@ trait Types{ types => trait TaggedReadWriter[T] extends ReadWriter[T] with TaggedReader[T] with TaggedWriter[T] with SimpleReader[T]{ override def visitArray(length: Int, index: Int) = taggedArrayContext(this, index) override def visitObject(length: Int, jsonableKeys: Boolean, index: Int) = taggedObjectContext(this, index) - } + object TaggedReadWriter{ - class Leaf[T](c: ClassTag[_], private[upickle] override val tagKey: String, tagValue: String, r: ObjectWriter[T] with Reader[T]) extends TaggedReadWriter[T]{ + class Leaf[T](c: ClassTag[_], + private[upickle] override val tagKey: String, + tagValue: String, r: ObjectWriter[T] with Reader[T]) extends TaggedReadWriter[T]{ @deprecated("Not used, left for binary compatibility") def this(c: ClassTag[_], tag: String, r: ObjectWriter[T] with Reader[T]) = this(c, Annotator.defaultTagKey, tag, r) @@ -308,28 +317,37 @@ class CurrentlyDeriving[T] * like Scala 2 `case object`s do, so we instead use a `Checker.Val` to check * for `.equals` equality during writes to determine which tag to use. */ +@scala.annotation.nowarn("msg=deprecated") trait Annotator { this: Types => + @deprecated("Not used, left for binary compatibility") def annotate[V](rw: Reader[V], n: String): TaggedReader[V] - // Calling deprecated method to maintain binary compatibility - @annotation.nowarn("msg=deprecated") - def annotate[V](rw: Reader[V], key: String, value: String): TaggedReader[V] = annotate(rw, value) + @deprecated("Not used, left for binary compatibility") + def annotate[V](rw: Reader[V], key: String, value: String): TaggedReader[V] = annotate(rw, value, value) + + def annotate[V](rw: Reader[V], key: String, value: String, shortValue: String): TaggedReader[V] = annotate(rw, value) @deprecated("Not used, left for binary compatibility") def annotate[V](rw: ObjectWriter[V], n: String, checker: Annotator.Checker): TaggedWriter[V] - // Calling deprecated method to maintain binary compatibility - @annotation.nowarn("msg=deprecated") + @deprecated("Not used, left for binary compatibility") def annotate[V](rw: ObjectWriter[V], key: String, value: String, checker: Annotator.Checker): TaggedWriter[V] = + annotate(rw, key, value, value, checker) + + def annotate[V](rw: ObjectWriter[V], key: String, value: String, shortValue: String, checker: Annotator.Checker): TaggedWriter[V] = annotate(rw, value, checker) + @deprecated("Not used, left for binary compatibility") def annotate[V](rw: ObjectWriter[V], key: String, value: String)(implicit ct: ClassTag[V]): TaggedWriter[V] = - annotate(rw, key, value, Annotator.Checker.Cls(ct.runtimeClass)) + annotate(rw, key, value, value)(ct) + + def annotate[V](rw: ObjectWriter[V], key: String, value: String, shortValue: String)(implicit ct: ClassTag[V]): TaggedWriter[V] = + annotate(rw, key, value, shortValue, Annotator.Checker.Cls(ct.runtimeClass)) @deprecated("Not used, left for binary compatibility") final def annotate[V](rw: ObjectWriter[V], n: String)(implicit ct: ClassTag[V]): TaggedWriter[V] = - annotate(rw, Annotator.defaultTagKey, n, Annotator.Checker.Cls(ct.runtimeClass)) + annotate(rw, Annotator.defaultTagKey, n, n, Annotator.Checker.Cls(ct.runtimeClass)) } object Annotator{ def defaultTagKey = "$type" diff --git a/upickle/implicits/src-2/upickle/implicits/internal/Macros.scala b/upickle/implicits/src-2/upickle/implicits/internal/Macros.scala index 4e064554d..060da9ce7 100644 --- a/upickle/implicits/src-2/upickle/implicits/internal/Macros.scala +++ b/upickle/implicits/src-2/upickle/implicits/internal/Macros.scala @@ -223,9 +223,31 @@ object Macros { (_: c.Symbol).name.toString, fail(tpe, _), ) - val tagValue = customKey(tpe.typeSymbol).getOrElse(TypeName(tpe.typeSymbol.fullName).decodedName.toString) - q"${c.prefix}.annotate($derived, $tagKey, $tagValue)" + + val segments = + sealedParents + .flatMap(_.asClass.knownDirectSubclasses) + .map(_.fullName.split('.')) + + // -1 because even if there is only one subclass, and so no name segments + // are needed to differentiate between them, we want to keep at least + // the rightmost name segment + val identicalSegmentCount = Range(0, segments.map(_.length).max - 1) + .takeWhile(i => segments.map(_.lift(i)).distinct.size == 1) + .length + + val tagValue = customKey(tpe.typeSymbol) + .getOrElse(TypeName(tpe.typeSymbol.fullName).decodedName.toString) + + val shortTagValue = customKey(tpe.typeSymbol) + .getOrElse( + TypeName( + tpe.typeSymbol.fullName.split('.').drop(identicalSegmentCount).mkString(".") + ).decodedName.toString + ) + + q"${c.prefix}.annotate($derived, $tagKey, $tagValue, $shortTagValue)" } } diff --git a/upickle/implicits/src-3/upickle/implicits/Readers.scala b/upickle/implicits/src-3/upickle/implicits/Readers.scala index d749e2a0f..a87057227 100644 --- a/upickle/implicits/src-3/upickle/implicits/Readers.scala +++ b/upickle/implicits/src-3/upickle/implicits/Readers.scala @@ -76,9 +76,19 @@ trait ReadersVersionSpecific } inline if macros.isSingleton[T] then - annotate[T](SingletonReader[T](macros.getSingleton[T]), macros.tagKey[T], macros.tagName[T]) + annotate[T]( + SingletonReader[T](macros.getSingleton[T]), + macros.tagKey[T], + macros.tagName[T], + macros.shortTagName[T] + ) else if macros.isMemberOfSealedHierarchy[T] then - annotate[T](reader, macros.tagKey[T], macros.tagName[T]) + annotate[T]( + reader, + macros.tagKey[T], + macros.tagName[T], + macros.shortTagName[T], + ) else reader case m: Mirror.SumOf[T] => @@ -101,7 +111,8 @@ trait ReadersVersionSpecific val actual = implicitly[Reader[V]].asInstanceOf[TaggedReader[T]] val tagKey = macros.tagKey[T] val tagName = macros.tagName[T] - new TaggedReader.Leaf(tagKey, tagName, actual.findReader(tagName)) + val shortTagName = macros.shortTagName[T] + new TaggedReader.Leaf(tagKey, tagName, shortTagName, actual.findReader(tagName)) } // see comment in MacroImplicits as to why Dotty's extension methods aren't used here diff --git a/upickle/implicits/src-3/upickle/implicits/Writers.scala b/upickle/implicits/src-3/upickle/implicits/Writers.scala index fb9d066d2..40e512320 100644 --- a/upickle/implicits/src-3/upickle/implicits/Writers.scala +++ b/upickle/implicits/src-3/upickle/implicits/Writers.scala @@ -48,6 +48,7 @@ trait WritersVersionSpecific SingletonWriter[T](null.asInstanceOf[T]), macros.tagKey[T], macros.tagName[T], + macros.shortTagName[T], Annotator.Checker.Val(macros.getSingleton[T]), ) else if macros.isMemberOfSealedHierarchy[T] then @@ -55,6 +56,7 @@ trait WritersVersionSpecific writer, macros.tagKey[T], macros.tagName[T], + macros.shortTagName[T], Annotator.Checker.Cls(implicitly[ClassTag[T]].runtimeClass), ) else writer diff --git a/upickle/implicits/src-3/upickle/implicits/macros.scala b/upickle/implicits/src-3/upickle/implicits/macros.scala index 814eb4274..b862a3d4a 100644 --- a/upickle/implicits/src-3/upickle/implicits/macros.scala +++ b/upickle/implicits/src-3/upickle/implicits/macros.scala @@ -199,6 +199,9 @@ def tagKeyImpl[T](using Quotes, Type[T]): Expr[String] = inline def tagName[T]: String = ${ tagNameImpl[T] } def tagNameImpl[T](using Quotes, Type[T]): Expr[String] = + tagNameImpl0(identity) + +def tagNameImpl0[T](transform: String => String)(using Quotes, Type[T]): Expr[String] = import quotes.reflect._ val sym = TypeTree.of[T].symbol @@ -228,9 +231,24 @@ def tagNameImpl[T](using Quotes, Type[T]): Expr[String] = case AppliedType(TypeRef(prefix, value), _) => value } } else { - TypeTree.of[T].tpe.typeSymbol.fullName.filter(_ != '$') + transform(TypeTree.of[T].tpe.typeSymbol.fullName.filter(_ != '$')) } ) +inline def shortTagName[T]: String = ${ shortTagNameImpl[T] } +def shortTagNameImpl[T](using Quotes, Type[T]): Expr[String] = + import quotes.reflect._ + val sym = TypeTree.of[T].symbol + val segments = TypeRepr.of[T].baseClasses + .filter(_.flags.is(Flags.Sealed)) + .flatMap(_.children) + .filter(_.flags.is(Flags.Case)) + .map(_.fullName.split('.')) + + val identicalSegmentCount = Range(0, segments.map(_.length).max - 1) + .takeWhile(i => segments.map(_.lift(i)).distinct.size == 1) + .length + + tagNameImpl0(_.split('.').drop(identicalSegmentCount).mkString(".")) inline def isSingleton[T]: Boolean = ${ isSingletonImpl[T] } def isSingletonImpl[T](using Quotes, Type[T]): Expr[Boolean] = diff --git a/upickle/implicits/src/upickle/implicits/MacrosCommon.scala b/upickle/implicits/src/upickle/implicits/MacrosCommon.scala index 4f2b1adf2..d7499d049 100644 --- a/upickle/implicits/src/upickle/implicits/MacrosCommon.scala +++ b/upickle/implicits/src/upickle/implicits/MacrosCommon.scala @@ -3,11 +3,42 @@ package upickle.implicits // Common things for derivation trait MacrosCommon { + /** + * Whether to use the fully-qualified name of `case class`es and `case object`s which + * are part of `sealed trait` hierarchies when serializing them and writing their `$type` + * key. Defaults to `false`, so `$type` key uses the shortest partially-qualified name. + * Can be set to `true` to use their fully-qualified name. + */ + def objectTypeKeyWriteFullyQualified: Boolean = false + + /** + * Whether or not to write `case class` keys which match their default values. + * Defaults to `false`, allowing those keys to be omitted. Can be set to `true` + * to always write field values even if they are equal to the default + */ def serializeDefaults: Boolean = false + /** + * Transform dictionary keys when writing `case class`es when reading. Can + * be overriden to provide custom mappings between Scala field names and JSON + * field names. Needs to be kept in sync with [[objectAttributeKeyWriteMap]] + * + * This customizes the mapping across all `case class`es fields handled by this + * upickle instance. This can be customized on a field-by-field basis using the + * [[upickle.implicits.key]] annotation on the `case class` field + */ def objectAttributeKeyReadMap(s: CharSequence): CharSequence = s def objectAttributeKeyWriteMap(s: CharSequence): CharSequence = s + /** + * Transforms the value of the `$type` field when writing `sealed trait`s, + * to allow custom mapping between the `case class` name and the `$type` field + * in the generated JSON. Must be kept in sync with [[objectTypeKeyWriteMap]]. + * + * * This customizes the mapping across all `case class`es fields handled by this + * * upickle instance. This can be customized on a per-`sealed trait` basis using the + * * [[upickle.implicits.key]] annotation on the `case class` + */ def objectTypeKeyReadMap(s: CharSequence): CharSequence = s def objectTypeKeyWriteMap(s: CharSequence): CharSequence = s diff --git a/upickle/src/upickle/Api.scala b/upickle/src/upickle/Api.scala index e3d8f5f42..a0e4c29ea 100644 --- a/upickle/src/upickle/Api.scala +++ b/upickle/src/upickle/Api.scala @@ -245,20 +245,27 @@ object default extends AttributeTagged{ */ object legacy extends LegacyApi trait LegacyApi extends Api with Annotator{ - override def annotate[V](rw: Reader[V], key: String, value: String) = { - new TaggedReader.Leaf[V](key, value, rw) + @deprecated("Not used, left for binary compatibility") + override def annotate[V](rw: Reader[V], key: String, value: String) = annotate(rw, key, value, value) + + override def annotate[V](rw: Reader[V], key: String, value: String, shortValue: String) = { + new TaggedReader.Leaf[V](key, value, shortValue, rw) } @deprecated("Not used, left for binary compatibility") override final def annotate[V](rw: Reader[V], n: String) = - annotate(rw, Annotator.defaultTagKey, n) + annotate(rw, Annotator.defaultTagKey, n, n) + @deprecated("Not used, left for binary compatibility") override def annotate[V](rw: ObjectWriter[V], key: String, value: String, checker: Annotator.Checker): TaggedWriter[V] = - new TaggedWriter.Leaf[V](checker, key, value, rw) + annotate(rw, key, value, value, checker) + + override def annotate[V](rw: ObjectWriter[V], key: String, value: String, shortValue: String, checker: Annotator.Checker): TaggedWriter[V] = + new TaggedWriter.Leaf[V](checker, key, if (objectTypeKeyWriteFullyQualified) value else shortValue, rw) @deprecated("Not used, left for binary compatibility") override final def annotate[V](rw: ObjectWriter[V], n: String, checker: Annotator.Checker): TaggedWriter[V] = - annotate(rw, Annotator.defaultTagKey, n, checker) + annotate(rw, Annotator.defaultTagKey, n, n, checker) def taggedExpectedMsg = "expected sequence" sealed trait TaggedReaderState @@ -318,19 +325,28 @@ trait AttributeTagged extends Api with Annotator{ @deprecated("Not used, left for binary compatibility") def tagName = Annotator.defaultTagKey - override def annotate[V](rw: Reader[V], key: String, value: String) = { - new TaggedReader.Leaf[V](key, value, rw) + @deprecated("Not used, left for binary compatibility") + override def annotate[V](rw: Reader[V], key: String, value: String) = annotate(rw, key, value, value) + + override def annotate[V](rw: Reader[V], key: String, value: String, shortValue: String) = { + new TaggedReader.Leaf[V](key, value, shortValue, rw) } @deprecated("Not used, left for binary compatibility") override final def annotate[V](rw: Reader[V], n: String) = - annotate(rw, Annotator.defaultTagKey, n) + annotate(rw, Annotator.defaultTagKey, n, n) + @deprecated("Not used, left for binary compatibility") override def annotate[V](rw: ObjectWriter[V], key: String, value: String, checker: Annotator.Checker): TaggedWriter[V] = { - new TaggedWriter.Leaf[V](checker, key, value, rw) + annotate(rw, key, value, value, checker) } + + override def annotate[V](rw: ObjectWriter[V], key: String, value: String, shortValue: String, checker: Annotator.Checker): TaggedWriter[V] = { + new TaggedWriter.Leaf[V](checker, key, if (objectTypeKeyWriteFullyQualified) value else shortValue, rw) + } + @deprecated("Not used, left for binary compatibility") override final def annotate[V](rw: ObjectWriter[V], n: String, checker: Annotator.Checker): TaggedWriter[V] = - annotate(rw, Annotator.defaultTagKey, n, checker) + annotate(rw, Annotator.defaultTagKey, n, n, checker) def taggedExpectedMsg = "expected dictionary" private def isTagName(tagKey: String, i: Any) = i match{ diff --git a/upickle/test/src-2/upickle/AdvancedTestsScala2Only.scala b/upickle/test/src-2/upickle/AdvancedTestsScala2Only.scala index 718e5c0f5..990fc43c5 100644 --- a/upickle/test/src-2/upickle/AdvancedTestsScala2Only.scala +++ b/upickle/test/src-2/upickle/AdvancedTestsScala2Only.scala @@ -20,16 +20,16 @@ object AdvancedTestsScala2Only extends TestSuite { test("gadt"){ test("simple"){ - test - rw(Gadt.Exists("hello"): Gadt[_], """{"$type":"upickle.Gadt.Exists","path":"hello"}""") - test - rw(Gadt.IsDir(" "): Gadt[_], """{"$type":"upickle.Gadt.IsDir","path":" "}""") - test - rw(Gadt.ReadBytes("\""): Gadt[_], """{"$type":"upickle.Gadt.ReadBytes","path":"\""}""") - test - rw(Gadt.CopyOver(Seq(1, 2, 3), ""): Gadt[_], """{"$type":"upickle.Gadt.CopyOver","src":[1,2,3],"path":""}""") + test - rw(Gadt.Exists("hello"): Gadt[_], """{"$type":"Exists","path":"hello"}""") + test - rw(Gadt.IsDir(" "): Gadt[_], """{"$type":"IsDir","path":" "}""") + test - rw(Gadt.ReadBytes("\""): Gadt[_], """{"$type":"ReadBytes","path":"\""}""") + test - rw(Gadt.CopyOver(Seq(1, 2, 3), ""): Gadt[_], """{"$type":"CopyOver","src":[1,2,3],"path":""}""") } test("partial"){ - test - rw(Gadt2.Exists("hello"): Gadt2[_, String], """{"$type":"upickle.Gadt2.Exists","v":"hello"}""") - test - rw(Gadt2.IsDir(123): Gadt2[_, Int], """{"$type":"upickle.Gadt2.IsDir","v":123}""") - test - rw(Gadt2.ReadBytes('h'): Gadt2[_, Char], """{"$type":"upickle.Gadt2.ReadBytes","v":"h"}""") - test - rw(Gadt2.CopyOver(Seq(1, 2, 3), ""): Gadt2[_, Unit], """{"$type":"upickle.Gadt2.CopyOver","src":[1,2,3],"v":""}""") + test - rw(Gadt2.Exists("hello"): Gadt2[_, String], """{"$type":"Exists","v":"hello"}""") + test - rw(Gadt2.IsDir(123): Gadt2[_, Int], """{"$type":"IsDir","v":123}""") + test - rw(Gadt2.ReadBytes('h'): Gadt2[_, Char], """{"$type":"ReadBytes","v":"h"}""") + test - rw(Gadt2.CopyOver(Seq(1, 2, 3), ""): Gadt2[_, Unit], """{"$type":"CopyOver","src":[1,2,3],"v":""}""") } } diff --git a/upickle/test/src-3/upickle/DerivationTests.scala b/upickle/test/src-3/upickle/DerivationTests.scala index ccd71ea6e..3bb05a0bf 100644 --- a/upickle/test/src-3/upickle/DerivationTests.scala +++ b/upickle/test/src-3/upickle/DerivationTests.scala @@ -59,13 +59,13 @@ object DerivationTests extends TestSuite { } test("animal"){ upickle.default.write(Person("Peter", "Ave 10")) ==> - """{"$type":"upickle.Person","name":"Peter","address":"Ave 10"}""" + """{"$type":"Person","name":"Peter","address":"Ave 10"}""" - upickle.default.read[Animal]("""{"$type":"upickle.Person","name":"Peter","address":"Ave 10"}""") ==> + upickle.default.read[Animal]("""{"$type":"Person","name":"Peter","address":"Ave 10"}""") ==> Person("Peter", "Ave 10") - upickle.default.write(Cthulu) ==> "\"upickle.Cthulu\"" - upickle.default.read[Animal]("\"upickle.Cthulu\"") ==> Cthulu + upickle.default.write(Cthulu) ==> "\"Cthulu\"" + upickle.default.read[Animal]("\"Cthulu\"") ==> Cthulu } } @@ -76,36 +76,36 @@ object DerivationTests extends TestSuite { test("caseClassTagged") - { rw[Person]( Person("Peter", "Avenue 10 Zurich", 20), - """{"$type":"upickle.Person","name":"Peter","address":"Avenue 10 Zurich"}""" + """{"$type":"Person","name":"Peter","address":"Avenue 10 Zurich"}""" ) } test("trait") - { rw[Animal]( Person("Peter", "Avenue 10 Zurich" ,20), - """{"$type":"upickle.Person","name":"Peter","address":"Avenue 10 Zurich"}""" + """{"$type":"Person","name":"Peter","address":"Avenue 10 Zurich"}""" ) rw[Animal]( Person("Peter", "Avenue 10 Zurich"), - """{"$type":"upickle.Person","name":"Peter","address":"Avenue 10 Zurich"}""" + """{"$type":"Person","name":"Peter","address":"Avenue 10 Zurich"}""" ) } test("caseObjectWriter") - { - rw[Animal](Cthulu, """"upickle.Cthulu"""", """{"$type":"upickle.Cthulu"}""") - rw[Cthulu.type](Cthulu, """"upickle.Cthulu"""", """{"$type":"upickle.Cthulu"}""") + rw[Animal](Cthulu, """"Cthulu"""", """{"$type":"Cthulu"}""") + rw[Cthulu.type](Cthulu, """"Cthulu"""", """{"$type":"Cthulu"}""") } test("caseObjectWriterImplicit") - { rw[AnimalImplicit]( CthuluImplicit, - """"upickle.CthuluImplicit"""", - """{"$type":"upickle.CthuluImplicit"}""" + """"CthuluImplicit"""", + """{"$type":"CthuluImplicit"}""" ) rw[CthuluImplicit.type]( CthuluImplicit, - """"upickle.CthuluImplicit"""", - """{"$type":"upickle.CthuluImplicit"}""" + """"CthuluImplicit"""", + """{"$type":"CthuluImplicit"}""" ) } @@ -115,53 +115,53 @@ object DerivationTests extends TestSuite { rw(Recur(Some(Recur(None))), """{"recur":[{"recur": []}]}""") } test("multilevel"){ - rw(Level1Cls(1), """{"$type": "upickle.Level1Cls", "i": 1}""") - rw(Level1Cls(1): Level1, """{"$type": "upickle.Level1Cls", "i": 1}""") + rw(Level1Cls(1), """{"$type": "Level1Cls", "i": 1}""") + rw(Level1Cls(1): Level1, """{"$type": "Level1Cls", "i": 1}""") - rw(Level1Obj, """"upickle.Level1Obj"""") - rw(Level1Obj: Level1, """"upickle.Level1Obj"""") + rw(Level1Obj, """"Level1Obj"""") + rw(Level1Obj: Level1, """"Level1Obj"""") - rw(Level2Cls("str"), """{"$type": "upickle.Level2Cls", "s": "str"}""") - rw(Level2Cls("str"): Level2, """{"$type": "upickle.Level2Cls", "s": "str"}""") - rw(Level2Cls("str"): Level1, """{"$type": "upickle.Level2Cls", "s": "str"}""") + rw(Level2Cls("str"), """{"$type": "Level2Cls", "s": "str"}""") + rw(Level2Cls("str"): Level2, """{"$type": "Level2Cls", "s": "str"}""") + rw(Level2Cls("str"): Level1, """{"$type": "Level2Cls", "s": "str"}""") - rw(Level2Obj, """"upickle.Level2Obj"""") - rw(Level2Obj: Level2, """"upickle.Level2Obj"""") - rw(Level2Obj: Level1, """"upickle.Level2Obj"""") + rw(Level2Obj, """"Level2Obj"""") + rw(Level2Obj: Level2, """"Level2Obj"""") + rw(Level2Obj: Level1, """"Level2Obj"""") - rw(Level3Cls(true), """{"$type": "upickle.Level3Cls", "b": true}""") - rw(Level3Cls(true): Level3, """{"$type": "upickle.Level3Cls", "b": true}""") - rw(Level3Cls(true): Level2, """{"$type": "upickle.Level3Cls", "b": true}""") - rw(Level3Cls(true): Level1, """{"$type": "upickle.Level3Cls", "b": true}""") + rw(Level3Cls(true), """{"$type": "Level3Cls", "b": true}""") + rw(Level3Cls(true): Level3, """{"$type": "Level3Cls", "b": true}""") + rw(Level3Cls(true): Level2, """{"$type": "Level3Cls", "b": true}""") + rw(Level3Cls(true): Level1, """{"$type": "Level3Cls", "b": true}""") - rw(Level3Obj, """"upickle.Level3Obj"""") - rw(Level3Obj: Level3, """"upickle.Level3Obj"""") - rw(Level3Obj: Level2, """"upickle.Level3Obj"""") - rw(Level3Obj: Level1, """"upickle.Level3Obj"""") + rw(Level3Obj, """"Level3Obj"""") + rw(Level3Obj: Level3, """"Level3Obj"""") + rw(Level3Obj: Level2, """"Level3Obj"""") + rw(Level3Obj: Level1, """"Level3Obj"""") } test("abstractClass"){ - rw(UnknownShirtSize, """ "upickle.UnknownShirtSize" """) - rw(UnknownShirtSize: ShirtSize, """ "upickle.UnknownShirtSize" """) - rw(XL, """ "upickle.XL" """) - rw(XL: ShirtSize, """ "upickle.XL" """) - rw(XL: KnownShirtSize, """ "upickle.XL" """) + rw(UnknownShirtSize, """ "UnknownShirtSize" """) + rw(UnknownShirtSize: ShirtSize, """ "UnknownShirtSize" """) + rw(XL, """ "XL" """) + rw(XL: ShirtSize, """ "XL" """) + rw(XL: KnownShirtSize, """ "XL" """) } test("failures"){ test("caseClassTaggedWrong") - { val e = intercept[upickle.core.AbortException] { upickle.default.read[Person]( - """{"$type":"upickle.Cat","name":"Peter","owner":{"$type":"upickle.Person","name": "bob", "address": "Avenue 10 Zurich"}}""" + """{"$type":"Cat","name":"Peter","owner":{"$type":"Person","name": "bob", "address": "Avenue 10 Zurich"}}""" ) } - assert(e.getMessage == "invalid tag for tagged object: upickle.Cat at index 9") + assert(e.getMessage == "invalid tag for tagged object: Cat at index 9") } test("multilevelTaggedWrong") - { val e = intercept[upickle.core.AbortException] { - upickle.default.read[Level2]("""{"$type": "upickle.Level1Cls", "i": 1}""") + upickle.default.read[Level2]("""{"$type": "Level1Cls", "i": 1}""") } - assert(e.getMessage == "invalid tag for tagged object: upickle.Level1Cls at index 10") + assert(e.getMessage == "invalid tag for tagged object: Level1Cls at index 10") } } test("issue468"){ diff --git a/upickle/test/src/upickle/AdvancedTests.scala b/upickle/test/src/upickle/AdvancedTests.scala index 2fe53033c..0d3caa681 100644 --- a/upickle/test/src/upickle/AdvancedTests.scala +++ b/upickle/test/src/upickle/AdvancedTests.scala @@ -138,26 +138,24 @@ object AdvancedTests extends TestSuite { test("ADT"){ import GenericADTs._ test - { - val pref1 = "upickle.GenericADTs.Delta" val D1 = Delta type D1[+A, +B] = Delta[A, B] - rw(D1.Insert(1, 1), s"""{"$$type":"$pref1.Insert","key":1,"value":1}""") - rw(D1.Insert(1, 1): D1[Int, Int], s"""{"$$type":"$pref1.Insert","key":1,"value":1}""") - rw(D1.Remove(1), s"""{"$$type":"$pref1.Remove","key":1}""") - rw(D1.Remove(1): D1[Int, Int], s"""{"$$type":"$pref1.Remove","key":1}""") - rw(D1.Clear(), s"""{"$$type":"$pref1.Clear"}""") - rw(D1.Clear(): D1[Int, Int], s"""{"$$type":"$pref1.Clear"}""") + rw(D1.Insert(1, 1), s"""{"$$type":"Insert","key":1,"value":1}""") + rw(D1.Insert(1, 1): D1[Int, Int], s"""{"$$type":"Insert","key":1,"value":1}""") + rw(D1.Remove(1), s"""{"$$type":"Remove","key":1}""") + rw(D1.Remove(1): D1[Int, Int], s"""{"$$type":"Remove","key":1}""") + rw(D1.Clear(), s"""{"$$type":"Clear"}""") + rw(D1.Clear(): D1[Int, Int], s"""{"$$type":"Clear"}""") } test - { - val pref2 = "upickle.GenericADTs.DeltaInvariant" val D2 = DeltaInvariant type D2[A, B] = DeltaInvariant[A, B] - rw(D2.Insert(1, 1), s"""{"$$type":"$pref2.Insert","key":1,"value":1}""") - rw(D2.Insert(1, 1): D2[Int, Int], s"""{"$$type":"$pref2.Insert","key":1,"value":1}""") - rw(D2.Remove(1), s"""{"$$type":"$pref2.Remove","key":1}""") - rw(D2.Remove(1): D2[Int, Int], s"""{"$$type":"$pref2.Remove","key":1}""") - rw(D2.Clear(), s"""{"$$type":"$pref2.Clear"}""") - rw(D2.Clear(): D2[Int, Int], s"""{"$$type":"$pref2.Clear"}""") + rw(D2.Insert(1, 1), s"""{"$$type":"Insert","key":1,"value":1}""") + rw(D2.Insert(1, 1): D2[Int, Int], s"""{"$$type":"Insert","key":1,"value":1}""") + rw(D2.Remove(1), s"""{"$$type":"Remove","key":1}""") + rw(D2.Remove(1): D2[Int, Int], s"""{"$$type":"Remove","key":1}""") + rw(D2.Clear(), s"""{"$$type":"Clear"}""") + rw(D2.Clear(): D2[Int, Int], s"""{"$$type":"Clear"}""") } } } @@ -177,16 +175,16 @@ object AdvancedTests extends TestSuite { rw( SingleNode(123, List(SingleNode(456, Nil), SingleNode(789, Nil))), """{ - "$type": "upickle.Recursive.SingleNode", + "$type": "SingleNode", "value": 123, "children": [ { - "$type": "upickle.Recursive.SingleNode", + "$type": "SingleNode", "value": 456, "children": [] }, { - "$type": "upickle.Recursive.SingleNode", + "$type": "SingleNode", "value":789, "children":[] } @@ -196,54 +194,54 @@ object AdvancedTests extends TestSuite { rw( SingleNode(123, List(SingleNode(456, Nil), SingleNode(789, Nil))): SingleTree, """{ - "$type": "upickle.Recursive.SingleNode", + "$type": "SingleNode", "value": 123, "children": [ { - "$type": "upickle.Recursive.SingleNode", + "$type": "SingleNode", "value": 456, "children": [] }, { - "$type": "upickle.Recursive.SingleNode", + "$type": "SingleNode", "value":789, "children":[] } ] }""" ) - rw(End: LL, """ "upickle.Recursive.End" """, """{"$type":"upickle.Recursive.End"}""") + rw(End: LL, """ "End" """, """{"$type":"End"}""") rw(Node(3, End): LL, """{ - "$type": "upickle.Recursive.Node", + "$type": "Node", "c": 3, - "next": "upickle.Recursive.End" + "next": "End" }""", """{ - "$type": "upickle.Recursive.Node", + "$type": "Node", "c": 3, - "next": {"$type":"upickle.Recursive.End"} + "next": {"$type":"End"} }""" ) rw( Node(6, Node(3, End)), """{ - "$type": "upickle.Recursive.Node", + "$type": "Node", "c": 6, "next": { - "$type": "upickle.Recursive.Node", + "$type": "Node", "c":3, - "next": "upickle.Recursive.End" + "next": "End" } }""", """{ - "$type": "upickle.Recursive.Node", + "$type": "Node", "c": 6, "next": { - "$type": "upickle.Recursive.Node", + "$type": "Node", "c":3, - "next":{"$type":"upickle.Recursive.End"} + "next":{"$type":"End"} } }""" ) @@ -251,24 +249,24 @@ object AdvancedTests extends TestSuite { } test("gadt"){ test("simple"){ - test - rw(Gadt.Exists("hello"), """{"$type":"upickle.Gadt.Exists","path":"hello"}""") -// test - rw(Gadt.Exists("hello"): Gadt[_], """{"$type":"upickle.Gadt.Exists","path":"hello"}""") - test - rw(Gadt.IsDir(" "), """{"$type":"upickle.Gadt.IsDir","path":" "}""") -// test - rw(Gadt.IsDir(" "): Gadt[_], """{"$type":"upickle.Gadt.IsDir","path":" "}""") - test - rw(Gadt.ReadBytes("\""), """{"$type":"upickle.Gadt.ReadBytes","path":"\""}""") -// test - rw(Gadt.ReadBytes("\""): Gadt[_], """{"$type":"upickle.Gadt.ReadBytes","path":"\""}""") - test - rw(Gadt.CopyOver(Seq(1, 2, 3), ""), """{"$type":"upickle.Gadt.CopyOver","src":[1,2,3],"path":""}""") -// test - rw(Gadt.CopyOver(Seq(1, 2, 3), ""): Gadt[_], """{"$type":"upickle.Gadt.CopyOver","src":[1,2,3],"path":""}""") + test - rw(Gadt.Exists("hello"), """{"$type":"Exists","path":"hello"}""") +// test - rw(Gadt.Exists("hello"): Gadt[_], """{"$type":"Exists","path":"hello"}""") + test - rw(Gadt.IsDir(" "), """{"$type":"IsDir","path":" "}""") +// test - rw(Gadt.IsDir(" "): Gadt[_], """{"$type":"IsDir","path":" "}""") + test - rw(Gadt.ReadBytes("\""), """{"$type":"ReadBytes","path":"\""}""") +// test - rw(Gadt.ReadBytes("\""): Gadt[_], """{"$type":"ReadBytes","path":"\""}""") + test - rw(Gadt.CopyOver(Seq(1, 2, 3), ""), """{"$type":"CopyOver","src":[1,2,3],"path":""}""") +// test - rw(Gadt.CopyOver(Seq(1, 2, 3), ""): Gadt[_], """{"$type":"CopyOver","src":[1,2,3],"path":""}""") } test("partial"){ - test - rw(Gadt2.Exists("hello"), """{"$type":"upickle.Gadt2.Exists","v":"hello"}""") -// test - rw(Gadt2.Exists("hello"): Gadt2[_, String], """{"$type":"upickle.Gadt2.Exists","v":"hello"}""") - test - rw(Gadt2.IsDir(123), """{"$type":"upickle.Gadt2.IsDir","v":123}""") -// test - rw(Gadt2.IsDir(123): Gadt2[_, Int], """{"$type":"upickle.Gadt2.IsDir","v":123}""") - test - rw(Gadt2.ReadBytes('h'), """{"$type":"upickle.Gadt2.ReadBytes","v":"h"}""") -// test - rw(Gadt2.ReadBytes('h'): Gadt2[_, Char], """{"$type":"upickle.Gadt2.ReadBytes","v":"h"}""") - test - rw(Gadt2.CopyOver(Seq(1, 2, 3), ""), """{"$type":"upickle.Gadt2.CopyOver","src":[1,2,3],"v":""}""") -// test - rw(Gadt2.CopyOver(Seq(1, 2, 3), ""): Gadt2[_, Unit], """{"$type":"upickle.Gadt2.CopyOver","src":[1,2,3],"v":""}""") + test - rw(Gadt2.Exists("hello"), """{"$type":"Exists","v":"hello"}""") +// test - rw(Gadt2.Exists("hello"): Gadt2[_, String], """{"$type":"Exists","v":"hello"}""") + test - rw(Gadt2.IsDir(123), """{"$type":"IsDir","v":123}""") +// test - rw(Gadt2.IsDir(123): Gadt2[_, Int], """{"$type":"IsDir","v":123}""") + test - rw(Gadt2.ReadBytes('h'), """{"$type":"ReadBytes","v":"h"}""") +// test - rw(Gadt2.ReadBytes('h'): Gadt2[_, Char], """{"$type":"ReadBytes","v":"h"}""") + test - rw(Gadt2.CopyOver(Seq(1, 2, 3), ""), """{"$type":"CopyOver","src":[1,2,3],"v":""}""") +// test - rw(Gadt2.CopyOver(Seq(1, 2, 3), ""): Gadt2[_, Unit], """{"$type":"CopyOver","src":[1,2,3],"v":""}""") } } test("issues"){ @@ -290,11 +288,11 @@ object AdvancedTests extends TestSuite { test("scalatex"){ val block = Ast.Block(1, Seq(Ast.Block.Text(2, "hello"))) val blockText = """{ - "$type":"upickle.Ast.Block", + "$type":"Block", "offset":1, "parts":[ { - "$type": "upickle.Ast.Block.Text", + "$type": "Block.Text", "offset":2, "txt":"hello" } @@ -307,7 +305,7 @@ object AdvancedTests extends TestSuite { val header = Ast.Header(0, "Hello", block) val headerText = s"""{ - "$$type": "upickle.Ast.Header", + "$$type": "Header", "offset": 0, "front": "Hello", "block": $blockText diff --git a/upickle/test/src/upickle/LegacyTests.scala b/upickle/test/src/upickle/LegacyTests.scala index 48768294e..e12376e85 100644 --- a/upickle/test/src/upickle/LegacyTests.scala +++ b/upickle/test/src/upickle/LegacyTests.scala @@ -4,7 +4,6 @@ import LegacyTestUtil.rw import upickle.legacy.{ReadWriter => RW, Reader => R, Writer => W} object LegacyTests extends TestSuite { - val tests = Tests { test("simpleAdt"){ implicit def ADT0rw: RW[ADTs.ADT0] = upickle.legacy.macroRW @@ -61,14 +60,14 @@ object LegacyTests extends TestSuite { implicit def AnZrw: RW[AnZ.type] = upickle.legacy.macroRW implicit def Zrw: RW[Z] = upickle.legacy.macroRW test("shallow"){ - test - rw(B(1), """["upickle.Hierarchy.B",{"i":1}]""") - test - rw(C("a", "b"), """["upickle.Hierarchy.C",{"s1":"a","s2":"b"}]""") + test - rw(B(1), """["B",{"i":1}]""") + test - rw(C("a", "b"), """["C",{"s1":"a","s2":"b"}]""") - test - rw(AnZ: Z, """["upickle.Hierarchy.AnZ",{}]""") - test - rw(AnZ, """["upickle.Hierarchy.AnZ",{}]""") + test - rw(AnZ: Z, """["AnZ",{}]""") + test - rw(AnZ, """["AnZ",{}]""") - test - rw(Hierarchy.B(1): Hierarchy.A, """["upickle.Hierarchy.B", {"i":1}]""") - test - rw(C("a", "b"): A, """["upickle.Hierarchy.C",{"s1":"a","s2":"b"}]""") + test - rw(Hierarchy.B(1): Hierarchy.A, """["B", {"i":1}]""") + test - rw(C("a", "b"): A, """["C",{"s1":"a","s2":"b"}]""") } test("deep"){ @@ -81,20 +80,20 @@ object LegacyTests extends TestSuite { implicit def Drw: RW[D] = upickle.legacy.macroRW implicit def Erw: RW[E] = upickle.legacy.macroRW implicit def Frw: RW[F] = upickle.legacy.macroRW - test - rw(B(1), """["upickle.DeepHierarchy.B",{"i":1}]""") - test - rw(B(1): A, """["upickle.DeepHierarchy.B",{"i":1}]""") - test - rw(AnQ(1): Q, """["upickle.DeepHierarchy.AnQ",{"i":1}]""") - test - rw(AnQ(1), """["upickle.DeepHierarchy.AnQ",{"i":1}]""") + test - rw(B(1), """["B",{"i":1}]""") + test - rw(B(1): A, """["B",{"i":1}]""") + test - rw(AnQ(1): Q, """["AnQ",{"i":1}]""") + test - rw(AnQ(1), """["AnQ",{"i":1}]""") - test - rw(F(AnQ(1)), """["upickle.DeepHierarchy.F",{"q":["upickle.DeepHierarchy.AnQ",{"i":1}]}]""") - test - rw(F(AnQ(2)): A, """["upickle.DeepHierarchy.F",{"q":["upickle.DeepHierarchy.AnQ",{"i":2}]}]""") - test - rw(F(AnQ(3)): C, """["upickle.DeepHierarchy.F",{"q":["upickle.DeepHierarchy.AnQ",{"i":3}]}]""") - test - rw(D("1"), """["upickle.DeepHierarchy.D",{"s":"1"}]""") - test - rw(D("1"): C, """["upickle.DeepHierarchy.D",{"s":"1"}]""") - test - rw(D("1"): A, """["upickle.DeepHierarchy.D",{"s":"1"}]""") - test - rw(E(true), """["upickle.DeepHierarchy.E",{"b":true}]""") - test - rw(E(true): C, """["upickle.DeepHierarchy.E",{"b":true}]""") - test - rw(E(true): A, """["upickle.DeepHierarchy.E",{"b":true}]""") + test - rw(F(AnQ(1)), """["F",{"q":["AnQ",{"i":1}]}]""") + test - rw(F(AnQ(2)): A, """["F",{"q":["AnQ",{"i":2}]}]""") + test - rw(F(AnQ(3)): C, """["F",{"q":["AnQ",{"i":3}]}]""") + test - rw(D("1"), """["D",{"s":"1"}]""") + test - rw(D("1"): C, """["D",{"s":"1"}]""") + test - rw(D("1"): A, """["D",{"s":"1"}]""") + test - rw(E(true), """["E",{"b":true}]""") + test - rw(E(true): C, """["E",{"b":true}]""") + test - rw(E(true): A, """["E",{"b":true}]""") } } test("singleton"){ @@ -103,10 +102,10 @@ object LegacyTests extends TestSuite { implicit def AArw: RW[AA] = legacy.macroRW implicit def BBrw: RW[BB.type] = legacy.macroRW implicit def CCrw: RW[CC.type] = legacy.macroRW - rw(BB, """["upickle.Singletons.BB",{}]""") - rw(CC, """["upickle.Singletons.CC",{}]""") - rw(BB: AA, """["upickle.Singletons.BB",{}]""") - rw(CC: AA, """["upickle.Singletons.CC",{}]""") + rw(BB, """["BB",{}]""") + rw(CC, """["CC",{}]""") + rw(BB: AA, """["BB",{}]""") + rw(CC: AA, """["CC",{}]""") } test("robustnessAgainstVaryingSchemas"){ test("renameKeysViaAnnotations"){ @@ -151,34 +150,32 @@ object LegacyTests extends TestSuite { test("generics"){ import GenericADTs._ test - { - val pref1 = "upickle.GenericADTs.Delta" val D1 = Delta implicit def Insertrw[A: R: W, B: R: W]: RW[D1.Insert[A, B]] = upickle.legacy.macroRW implicit def Removerw[A: R: W]: RW[D1.Remove[A]] = upickle.legacy.macroRW implicit def Clearrw: RW[D1.Clear] = upickle.legacy.macroRW implicit def D1rw[A: R: W, B: R: W]: RW[D1[A, B]] = upickle.legacy.macroRW type D1[+A, +B] = Delta[A, B] - rw(D1.Insert(1, 1), s"""["$pref1.Insert",{"key":1,"value":1}]""") - rw(D1.Insert(1, 1): D1[Int, Int], s"""["$pref1.Insert",{"key":1,"value":1}]""") - rw(D1.Remove(1), s"""["$pref1.Remove",{"key":1}]""") - rw(D1.Remove(1): D1[Int, Int], s"""["$pref1.Remove",{"key":1}]""") - rw(D1.Clear(), s"""["$pref1.Clear",{}]""") - rw(D1.Clear(): D1[Int, Int], s"""["$pref1.Clear",{}]""") + rw(D1.Insert(1, 1), s"""["Insert",{"key":1,"value":1}]""") + rw(D1.Insert(1, 1): D1[Int, Int], s"""["Insert",{"key":1,"value":1}]""") + rw(D1.Remove(1), s"""["Remove",{"key":1}]""") + rw(D1.Remove(1): D1[Int, Int], s"""["Remove",{"key":1}]""") + rw(D1.Clear(), s"""["Clear",{}]""") + rw(D1.Clear(): D1[Int, Int], s"""["Clear",{}]""") } test - { - val pref2 = "upickle.GenericADTs.DeltaInvariant" val D2 = DeltaInvariant type D2[A, B] = DeltaInvariant[A, B] implicit def Insertrw[A: R: W, B: R: W]: RW[D2.Insert[A, B]] = upickle.legacy.macroRW implicit def Removerw[A: R: W, B]: RW[D2.Remove[A, B]] = upickle.legacy.macroRW implicit def Clearrw[A, B]: RW[D2.Clear[A, B]] = upickle.legacy.macroRW implicit def D2rw[A: R: W, B: R: W]: RW[D2[A, B]] = upickle.legacy.macroRW - rw(D2.Insert(1, 1), s"""["$pref2.Insert",{"key":1,"value":1}]""") - rw(D2.Insert(1, 1): D2[Int, Int], s"""["$pref2.Insert",{"key":1,"value":1}]""") - rw(D2.Remove(1), s"""["$pref2.Remove",{"key":1}]""") - rw(D2.Remove(1): D2[Int, Int], s"""["$pref2.Remove",{"key":1}]""") - rw(D2.Clear(), s"""["$pref2.Clear",{}]""") - rw(D2.Clear(): D2[Int, Int], s"""["$pref2.Clear",{}]""") + rw(D2.Insert(1, 1), s"""["Insert",{"key":1,"value":1}]""") + rw(D2.Insert(1, 1): D2[Int, Int], s"""["Insert",{"key":1,"value":1}]""") + rw(D2.Remove(1), s"""["Remove",{"key":1}]""") + rw(D2.Remove(1): D2[Int, Int], s"""["Remove",{"key":1}]""") + rw(D2.Clear(), s"""["Clear",{}]""") + rw(D2.Clear(): D2[Int, Int], s"""["Clear",{}]""") } } test("recursiveDataTypes"){ @@ -200,15 +197,15 @@ object LegacyTests extends TestSuite { ) rw( SingleNode(123, List(SingleNode(456, Nil), SingleNode(789, Nil))), - """["upickle.Recursive.SingleNode",{"value":123,"children":[["upickle.Recursive.SingleNode",{"value":456,"children":[]}],["upickle.Recursive.SingleNode",{"value":789,"children":[]}]]}]""" + """["SingleNode",{"value":123,"children":[["SingleNode",{"value":456,"children":[]}],["SingleNode",{"value":789,"children":[]}]]}]""" ) rw( SingleNode(123, List(SingleNode(456, Nil), SingleNode(789, Nil))): SingleTree, - """["upickle.Recursive.SingleNode",{"value":123,"children":[["upickle.Recursive.SingleNode",{"value":456,"children":[]}],["upickle.Recursive.SingleNode",{"value":789,"children":[]}]]}]""" + """["SingleNode",{"value":123,"children":[["SingleNode",{"value":456,"children":[]}],["SingleNode",{"value":789,"children":[]}]]}]""" ) - rw(End: LL, """["upickle.Recursive.End",{}]""") - rw(Node(3, End): LL, """["upickle.Recursive.Node",{"c":3,"next":["upickle.Recursive.End",{}]}]""") - rw(Node(6, Node(3, End)), """["upickle.Recursive.Node",{"c":6,"next":["upickle.Recursive.Node",{"c":3,"next":["upickle.Recursive.End",{}]}]}]""") + rw(End: LL, """["End",{}]""") + rw(Node(3, End): LL, """["Node",{"c":3,"next":["End",{}]}]""") + rw(Node(6, Node(3, End)), """["Node",{"c":6,"next":["Node",{"c":3,"next":["End",{}]}]}]""") } test("varargs"){ @@ -253,12 +250,12 @@ object LegacyTests extends TestSuite { implicit def rw12: RW[Ast.Chain.Args] = legacy.macroRW val block = Ast.Block(1, Seq(Ast.Block.Text(2, "hello"))) val blockText = """[ - "upickle.Ast.Block", + "Block", { "offset":1, "parts":[ [ - "upickle.Ast.Block.Text", + "Block.Text", { "offset":2, "txt":"hello" @@ -274,7 +271,7 @@ object LegacyTests extends TestSuite { val header = Ast.Header(0, "Hello", block) val headerText = s"""[ - "upickle.Ast.Header", + "Header", { "offset": 0, "front": "Hello", diff --git a/upickle/test/src/upickle/MacroTests.scala b/upickle/test/src/upickle/MacroTests.scala index 02b8077ed..6d9be3965 100644 --- a/upickle/test/src/upickle/MacroTests.scala +++ b/upickle/test/src/upickle/MacroTests.scala @@ -252,8 +252,13 @@ object MacroTests extends TestSuite { test("shallow"){ test - rw( B(1), + """{"$type": "B", "i":1}""", """{"$type": "upickle.Hierarchy.B", "i":1}""", """{"i":1, "$type": "upickle.Hierarchy.B"}""", + upack.Obj( + upack.Str("$type") -> upack.Str("B"), + upack.Str("i") -> upack.Int32(1) + ), upack.Obj( upack.Str("$type") -> upack.Str("upickle.Hierarchy.B"), upack.Str("i") -> upack.Int32(1) @@ -265,8 +270,14 @@ object MacroTests extends TestSuite { ) test - rw( C("a", "b"), + """{"$type": "C", "s1":"a","s2":"b"}""", """{"$type": "upickle.Hierarchy.C", "s1":"a","s2":"b"}""", """{"s1":"a","s2":"b", "$type": "upickle.Hierarchy.C"}""", + upack.Obj( + upack.Str("$type") -> upack.Str("C"), + upack.Str("s1") -> upack.Str("a"), + upack.Str("s2") -> upack.Str("b") + ), upack.Obj( upack.Str("$type") -> upack.Str("upickle.Hierarchy.C"), upack.Str("s1") -> upack.Str("a"), @@ -280,22 +291,31 @@ object MacroTests extends TestSuite { ) test - rw( AnZ: Z, + """ "AnZ" """, """ "upickle.Hierarchy.AnZ" """, """{"$type": "upickle.Hierarchy.AnZ"}""", + upack.Str("AnZ"), upack.Str("upickle.Hierarchy.AnZ"), upack.Obj(upack.Str("$type") -> upack.Str("upickle.Hierarchy.AnZ")) ) test - rw( AnZ, + """ "AnZ" """, """ "upickle.Hierarchy.AnZ" """, """{"$type": "upickle.Hierarchy.AnZ"}""", + upack.Str("AnZ"), upack.Str("upickle.Hierarchy.AnZ"), upack.Obj(upack.Str("$type") -> upack.Str("upickle.Hierarchy.AnZ")) ) test - rw( Hierarchy.B(1): Hierarchy.A, + """{"$type": "B", "i":1}""", """{"$type": "upickle.Hierarchy.B", "i":1}""", """{"i":1, "$type": "upickle.Hierarchy.B"}""", + upack.Obj( + upack.Str("$type") -> upack.Str("B"), + upack.Str("i") -> upack.Int32(1) + ), upack.Obj( upack.Str("$type") -> upack.Str("upickle.Hierarchy.B"), upack.Str("i") -> upack.Int32(1) @@ -307,8 +327,14 @@ object MacroTests extends TestSuite { ) test - rw( C("a", "b"): A, + """{"$type": "C", "s1":"a","s2":"b"}""", """{"$type": "upickle.Hierarchy.C", "s1":"a","s2":"b"}""", """{"s1":"a","s2":"b", "$type": "upickle.Hierarchy.C"}""", + upack.Obj( + upack.Str("$type") -> upack.Str("C"), + upack.Str("s1") -> upack.Str("a"), + upack.Str("s2") -> upack.Str("b") + ), upack.Obj( upack.Str("$type") -> upack.Str("upickle.Hierarchy.C"), upack.Str("s1") -> upack.Str("a"), @@ -327,7 +353,12 @@ object MacroTests extends TestSuite { test - rw( B(1), + """{"$type": "B", "i":1}""", """{"$type": "upickle.DeepHierarchy.B", "i":1}""", + upack.Obj( + upack.Str("$type") -> upack.Str("B"), + upack.Str("i") -> upack.Int32(1) + ), upack.Obj( upack.Str("$type") -> upack.Str("upickle.DeepHierarchy.B"), upack.Str("i") -> upack.Int32(1) @@ -335,7 +366,12 @@ object MacroTests extends TestSuite { ) test - rw( B(1): A, + """{"$type": "B", "i":1}""", """{"$type": "upickle.DeepHierarchy.B", "i":1}""", + upack.Obj( + upack.Str("$type") -> upack.Str("B"), + upack.Str("i") -> upack.Int32(1) + ), upack.Obj( upack.Str("$type") -> upack.Str("upickle.DeepHierarchy.B"), upack.Str("i") -> upack.Int32(1) @@ -343,7 +379,12 @@ object MacroTests extends TestSuite { ) test - rw( AnQ(1): Q, + """{"$type": "AnQ", "i":1}""", """{"$type": "upickle.DeepHierarchy.AnQ", "i":1}""", + upack.Obj( + upack.Str("$type") -> upack.Str("AnQ"), + upack.Str("i") -> upack.Int32(1) + ), upack.Obj( upack.Str("$type") -> upack.Str("upickle.DeepHierarchy.AnQ"), upack.Str("i") -> upack.Int32(1) @@ -351,7 +392,12 @@ object MacroTests extends TestSuite { ) test - rw( AnQ(1), + """{"$type": "AnQ","i":1}""", """{"$type": "upickle.DeepHierarchy.AnQ","i":1}""", + upack.Obj( + upack.Str("$type") -> upack.Str("AnQ"), + upack.Str("i") -> upack.Int32(1) + ), upack.Obj( upack.Str("$type") -> upack.Str("upickle.DeepHierarchy.AnQ"), upack.Str("i") -> upack.Int32(1) @@ -360,7 +406,15 @@ object MacroTests extends TestSuite { test - rw( F(AnQ(1)), + """{"$type": "F","q":{"$type":"AnQ", "i":1}}""", """{"$type": "upickle.DeepHierarchy.F","q":{"$type":"upickle.DeepHierarchy.AnQ", "i":1}}""", + upack.Obj( + upack.Str("$type") -> upack.Str("F"), + upack.Str("q") -> upack.Obj( + upack.Str("$type") -> upack.Str("AnQ"), + upack.Str("i") -> upack.Int32(1) + ) + ), upack.Obj( upack.Str("$type") -> upack.Str("upickle.DeepHierarchy.F"), upack.Str("q") -> upack.Obj( @@ -371,7 +425,15 @@ object MacroTests extends TestSuite { ) test - rw( F(AnQ(2)): A, + """{"$type": "F","q":{"$type":"AnQ", "i":2}}""", """{"$type": "upickle.DeepHierarchy.F","q":{"$type":"upickle.DeepHierarchy.AnQ", "i":2}}""", + upack.Obj( + upack.Str("$type") -> upack.Str("F"), + upack.Str("q") -> upack.Obj( + upack.Str("$type") -> upack.Str("AnQ"), + upack.Str("i") -> upack.Int32(2) + ) + ), upack.Obj( upack.Str("$type") -> upack.Str("upickle.DeepHierarchy.F"), upack.Str("q") -> upack.Obj( @@ -382,7 +444,15 @@ object MacroTests extends TestSuite { ) test - rw( F(AnQ(3)): C, + """{"$type": "F","q":{"$type":"AnQ", "i":3}}""", """{"$type": "upickle.DeepHierarchy.F","q":{"$type":"upickle.DeepHierarchy.AnQ", "i":3}}""", + upack.Obj( + upack.Str("$type") -> upack.Str("F"), + upack.Str("q") -> upack.Obj( + upack.Str("$type") -> upack.Str("AnQ"), + upack.Str("i") -> upack.Int32(3) + ) + ), upack.Obj( upack.Str("$type") -> upack.Str("upickle.DeepHierarchy.F"), upack.Str("q") -> upack.Obj( @@ -393,7 +463,12 @@ object MacroTests extends TestSuite { ) test - rw( D("1"), + """{"$type": "D", "s":"1"}""", """{"$type": "upickle.DeepHierarchy.D", "s":"1"}""", + upack.Obj( + upack.Str("$type") -> upack.Str("D"), + upack.Str("s") -> upack.Str("1") + ), upack.Obj( upack.Str("$type") -> upack.Str("upickle.DeepHierarchy.D"), upack.Str("s") -> upack.Str("1") @@ -401,7 +476,12 @@ object MacroTests extends TestSuite { ) test - rw( D("1"): C, + """{"$type": "D", "s":"1"}""", """{"$type": "upickle.DeepHierarchy.D", "s":"1"}""", + upack.Obj( + upack.Str("$type") -> upack.Str("D"), + upack.Str("s") -> upack.Str("1") + ), upack.Obj( upack.Str("$type") -> upack.Str("upickle.DeepHierarchy.D"), upack.Str("s") -> upack.Str("1") @@ -409,7 +489,12 @@ object MacroTests extends TestSuite { ) test - rw( D("1"): A, + """{"$type": "D", "s":"1"}""", """{"$type": "upickle.DeepHierarchy.D", "s":"1"}""", + upack.Obj( + upack.Str("$type") -> upack.Str("D"), + upack.Str("s") -> upack.Str("1") + ), upack.Obj( upack.Str("$type") -> upack.Str("upickle.DeepHierarchy.D"), upack.Str("s") -> upack.Str("1") @@ -417,7 +502,12 @@ object MacroTests extends TestSuite { ) test - rw( E(true), + """{"$type": "E", "b":true}""", """{"$type": "upickle.DeepHierarchy.E", "b":true}""", + upack.Obj( + upack.Str("$type") -> upack.Str("E"), + upack.Str("b") -> upack.True + ), upack.Obj( upack.Str("$type") -> upack.Str("upickle.DeepHierarchy.E"), upack.Str("b") -> upack.True @@ -425,7 +515,12 @@ object MacroTests extends TestSuite { ) test - rw( E(true): C, + """{"$type": "E","b":true}""", """{"$type": "upickle.DeepHierarchy.E","b":true}""", + upack.Obj( + upack.Str("$type") -> upack.Str("E"), + upack.Str("b") -> upack.True + ), upack.Obj( upack.Str("$type") -> upack.Str("upickle.DeepHierarchy.E"), upack.Str("b") -> upack.True @@ -433,7 +528,12 @@ object MacroTests extends TestSuite { ) test - rw( E(true): A, + """{"$type": "E", "b":true}""", """{"$type": "upickle.DeepHierarchy.E", "b":true}""", + upack.Obj( + upack.Str("$type") -> upack.Str("E"), + upack.Str("b") -> upack.True + ), upack.Obj( upack.Str("$type") -> upack.Str("upickle.DeepHierarchy.E"), upack.Str("b") -> upack.True @@ -446,29 +546,37 @@ object MacroTests extends TestSuite { rw( BB, + """ "BB" """, """ "upickle.Singletons.BB" """, """{"$type":"upickle.Singletons.BB"}""", + upack.Str("BB"), upack.Str("upickle.Singletons.BB"), upack.Obj(upack.Str("$type") -> upack.Str("upickle.Singletons.BB")) ) rw( CC, + """ "CC" """, """ "upickle.Singletons.CC" """, """{"$type":"upickle.Singletons.CC"}""", + upack.Str("CC"), upack.Str("upickle.Singletons.CC"), upack.Obj(upack.Str("$type") -> upack.Str("upickle.Singletons.CC")) ) rw( BB: AA, + """ "BB" """, """ "upickle.Singletons.BB" """, """{"$type":"upickle.Singletons.BB"}""", + upack.Str("BB"), upack.Str("upickle.Singletons.BB"), upack.Obj(upack.Str("$type") -> upack.Str("upickle.Singletons.BB")) ) rw( CC: AA, + """ "CC" """, """ "upickle.Singletons.CC" """, """{"$type":"upickle.Singletons.CC"}""", + upack.Str("CC"), upack.Str("upickle.Singletons.CC"), upack.Obj(upack.Str("$type") -> upack.Str("upickle.Singletons.CC")) ) @@ -616,10 +724,26 @@ object MacroTests extends TestSuite { } test("specialchars"){ - rw(SpecialChars.`+1`(), """{"$type": "upickle.SpecialChars.+1"}""") - rw(SpecialChars.`+1`(1), """{"$type": "upickle.SpecialChars.+1", "+1": 1}""") - rw(SpecialChars.`-1`(), """{"$type": "upickle.SpecialChars.-1"}""") - rw(SpecialChars.`-1`(1), """{"$type": "upickle.SpecialChars.-1", "-1": 1}""") + rw( + SpecialChars.`+1`(), + """{"$type": "+1"}""", + """{"$type": "upickle.SpecialChars.+1"}""", + ) + rw( + SpecialChars.`+1`(1), + """{"$type": "+1", "+1": 1}""", + """{"$type": "upickle.SpecialChars.+1", "+1": 1}""" + ) + rw( + SpecialChars.`-1`(), + """{"$type": "-1"}""", + """{"$type": "upickle.SpecialChars.-1"}""", + ) + rw( + SpecialChars.`-1`(1), + """{"$type": "-1", "-1": 1}""", + """{"$type": "upickle.SpecialChars.-1", "-1": 1}""", + ) } test("genericIssue545"){ @@ -663,11 +787,11 @@ object MacroTests extends TestSuite { } test("keyedADT") { - val fooJson = "\"upickle.KeyedADT.Foo\"" + val fooJson = "\"Foo\"" upickle.default.read[KeyedADT](fooJson) ==> KeyedADT.Foo upickle.default.write[KeyedADT](KeyedADT.Foo) ==> fooJson - val barJson = """{"customKey":"upickle.KeyedADT.Bar","i":1}""" + val barJson = """{"customKey":"Bar","i":1}""" upickle.default.read[KeyedADT](barJson) ==> KeyedADT.Bar(1) upickle.default.write[KeyedADT](KeyedADT.Bar(1)) ==> barJson } @@ -679,5 +803,51 @@ object MacroTests extends TestSuite { compileError("upickle.default.macroRW[upickle.SomeMultiKeyedObj.type]") .check("", "inherits from multiple parent types with different discriminator keys") } + + test("multiKeyedADT") { + compileError("upickle.default.macroRW[upickle.MultiKeyedObj.type]") + .check("", "inherits from multiple parent types with different discriminator keys") + + compileError("upickle.default.macroRW[upickle.SomeMultiKeyedObj.type]") + .check("", "inherits from multiple parent types with different discriminator keys") + } + + test("objectTypeKeyWriteFullyQualified") { + object customPickler extends upickle.AttributeTagged { + override def objectTypeKeyWriteFullyQualified = true + } + + val customPicklerTest = new TestUtil(customPickler) + + implicit def rwA: customPickler.ReadWriter[upickle.Hierarchy.A] = customPickler.macroRW + implicit def rwB: customPickler.ReadWriter[upickle.Hierarchy.B] = customPickler.macroRW + implicit def rwC: customPickler.ReadWriter[upickle.Hierarchy.C] = customPickler.macroRW + + // Make sure both custom pickler and default pickler can read both long and short `$type` tags, + // but that the custom pickler generates the long `$type` tag while the default pickler + // generates the short one + customPicklerTest.rw( + new Hierarchy.B(1), + """{"$type": "upickle.Hierarchy.B", "i": 1}""", + """{"$type": "B", "i": 1}""" + ) + rw( + new Hierarchy.B(1), + """{"$type": "B", "i": 1}""", + """{"$type": "upickle.Hierarchy.B", "i": 1}""" + ) + + customPicklerTest.rw( + new Hierarchy.C("x", "y"), + """{"$type": "upickle.Hierarchy.C", "s1": "x", "s2": "y"}""", + """{"$type": "C", "s1": "x", "s2": "y"}""" + ) + rw( + new Hierarchy.C("x", "y"), + """{"$type": "C", "s1": "x", "s2": "y"}""", + """{"$type": "upickle.Hierarchy.C", "s1": "x", "s2": "y"}""" + ) + + } } } diff --git a/upickle/test/src/upickle/example/ExampleTests.scala b/upickle/test/src/upickle/example/ExampleTests.scala index fc8306c5b..57bd9a41d 100644 --- a/upickle/test/src/upickle/example/ExampleTests.scala +++ b/upickle/test/src/upickle/example/ExampleTests.scala @@ -243,14 +243,14 @@ object ExampleTests extends TestSuite { test("sealed"){ - write(IntThing(1)) ==> """{"$type":"upickle.example.Sealed.IntThing","i":1}""" + write(IntThing(1)) ==> """{"$type":"IntThing","i":1}""" write(TupleThing("naeem", (1, 2))) ==> - """{"$type":"upickle.example.Sealed.TupleThing","name":"naeem","t":[1,2]}""" + """{"$type":"TupleThing","name":"naeem","t":[1,2]}""" // You can read tagged value without knowing its // type in advance, just use type of the sealed trait - read[IntOrTuple]("""{"$type":"upickle.example.Sealed.IntThing","i":1}""") ==> IntThing(1) + read[IntOrTuple]("""{"$type":"IntThing","i":1}""") ==> IntThing(1) } test("recursive"){ @@ -323,9 +323,9 @@ object ExampleTests extends TestSuite { } test("tagKey"){ write(ATag(11)) ==> - """{"_tag":"upickle.example.KeyedTagKey.ATag","i":11}""" + """{"_tag":"ATag","i":11}""" - read[ATag]("""{"_tag":"upickle.example.KeyedTagKey.ATag","i":11}""") ==> + read[ATag]("""{"_tag":"ATag","i":11}""") ==> ATag(11) } test("snakeCase"){