diff --git a/SCALA-3-MIGRATION-GUIDE.md b/SCALA-3-MIGRATION-GUIDE.md new file mode 100644 index 00000000..676c8daf --- /dev/null +++ b/SCALA-3-MIGRATION-GUIDE.md @@ -0,0 +1,44 @@ +# Scala 3 migration guide + +### How to cross-compile + +If you want to compile the same codebase with both scala-2 and scala-3, +you need to port the following methods. + +```scala +// JSON derivation +// Why?: These methods are internal and shouldn't be exposed +jsonProduct(CaseClass.apply _) -> deriveJSON +toJsonProduct(CaseClass.apply _) -> deriveToJSON +toJsonProduct0(CaseObject) -> deriveToJSON +fromJsonProduct(CaseClass.apply _) -> deriveFromJSON +fromJsonProduct(CaseObject) -> deriveFromJSON + +// deriveJSON dropping Enumeration support +// Why?: There's no derivation required for Enumeration +deriveJSON[SomeEnumeration.Value] -> jsonEnum(Enumeration) + +// MongoFormat derivation +// Why?: These methods are internal and shouldn't be exposed +mongoProduct(CaseClass.apply _) -> deriveMongoFormat +mongoProduct0(CaseObject) -> deriveMongoFormat + +// TypeSelectorContainer removed +// Why?: TypeSelectorContainer is internal and shouldn't be exposed. +json.asInstanceOf[TypeSelectorContainer].typeSelectors.map(_.typeValue) +-> +json.subTypeNames + +``` + +### Deprecated methods + +The following methods will not be continued and no alternatives will be provided (because they are not used in our +codebase): + +```scala +toJsonSingletonEnumSwitch +fromJsonSingletonEnumSwitch +``` + + diff --git a/json/json-core/src/main/scala/io/sphere/json/JSON.scala b/json/json-core/src/main/scala/io/sphere/json/JSON.scala index 3e2366a2..a9820039 100644 --- a/json/json-core/src/main/scala/io/sphere/json/JSON.scala +++ b/json/json-core/src/main/scala/io/sphere/json/JSON.scala @@ -5,7 +5,12 @@ import org.json4s.JsonAST.JValue import scala.annotation.implicitNotFound @implicitNotFound("Could not find an instance of JSON for ${A}") -trait JSON[A] extends FromJSON[A] with ToJSON[A] +trait JSON[A] extends FromJSON[A] with ToJSON[A] { + + // This field is only used in case we derive a trait, for classes/objects it remains empty + // It uses the JSON names not the Scala names (if there's @JSONTypeHint renaming a class the renamed name is used here) + def subTypeNames: List[String] = Nil +} object JSON extends JSONInstances with JSONLowPriorityImplicits { @inline def apply[A](implicit instance: JSON[A]): JSON[A] = instance diff --git a/json/json-derivation/src/main/scala/io/sphere/json/generic/JSONMacros.scala b/json/json-derivation/src/main/scala/io/sphere/json/generic/JSONMacros.scala index e7d6a60a..7818ef07 100644 --- a/json/json-derivation/src/main/scala/io/sphere/json/generic/JSONMacros.scala +++ b/json/json-derivation/src/main/scala/io/sphere/json/generic/JSONMacros.scala @@ -134,6 +134,72 @@ private[generic] object JSONMacros { } } + def generateJsonProduct( + c: blackbox.Context)(tpe: c.universe.Type, classSym: c.universe.ClassSymbol)( + classFnName: String, + objectFnName: String): c.universe.Tree = { + import c.universe._ + + if (classSym.isCaseClass && !classSym.isModuleClass) { + val classSymType = classSym.toType + val argList = classSymType.member(termNames.CONSTRUCTOR).asMethod.paramLists.head + val modifiers = Modifiers(Flag.PARAM) + val (argDefs, args) = (for ((a, i) <- argList.zipWithIndex) yield { + val argType = classSymType.member(a.name).typeSignatureIn(tpe) + val termName = TermName("x" + i) + val argTree = ValDef(modifiers, termName, TypeTree(argType), EmptyTree) + (argTree, Ident(termName)) + }).unzip + + val applyBlock = Block( + Nil, + Function( + argDefs, + Apply(Select(Ident(classSym.companion), TermName("apply")), args) + )) + Apply( + Select( + reify(io.sphere.json.generic.`package`).tree, + TermName(classFnName) + ), + applyBlock :: Nil + ) + } else if (classSym.isCaseClass && classSym.isModuleClass) { + Apply( + Select( + reify(io.sphere.json.generic.`package`).tree, + TermName(objectFnName) + ), + Ident(classSym.name.toTermName) :: Nil + ) + } else c.abort(c.enclosingPosition, "Not a case class or (case) object") + } + def deriveToJSON_impl[A: c.WeakTypeTag](c: blackbox.Context): c.Expr[ToJSON[A]] = { + import c.universe._ + + val tpe = weakTypeOf[A] + val symbol = tpe.typeSymbol + + if (symbol.isClass && (symbol.asClass.isCaseClass || symbol.asClass.isModuleClass)) + c.Expr[ToJSON[A]]( + generateJsonProduct(c)(tpe, symbol.asClass)("toJsonProduct", "toJsonProduct0")) + else + c.abort(c.enclosingPosition, "Not a case class or (case) object") + } + + def deriveFromJSON_impl[A: c.WeakTypeTag](c: blackbox.Context): c.Expr[FromJSON[A]] = { + import c.universe._ + + val tpe = weakTypeOf[A] + val symbol = tpe.typeSymbol + + if (symbol.isClass && (symbol.asClass.isCaseClass || symbol.asClass.isModuleClass)) + c.Expr[FromJSON[A]]( + generateJsonProduct(c)(tpe, symbol.asClass)("fromJsonProduct", "fromJsonProduct0")) + else + c.abort(c.enclosingPosition, "Not a case class or (case) object") + } + def deriveJSON_impl[A: c.WeakTypeTag](c: blackbox.Context): c.Expr[JSON[A]] = { import c.universe._ diff --git a/json/json-derivation/src/main/scala/io/sphere/json/generic/package.fmpp.scala b/json/json-derivation/src/main/scala/io/sphere/json/generic/package.fmpp.scala index d50e7afc..c84b9987 100644 --- a/json/json-derivation/src/main/scala/io/sphere/json/generic/package.fmpp.scala +++ b/json/json-derivation/src/main/scala/io/sphere/json/generic/package.fmpp.scala @@ -29,6 +29,9 @@ package object generic extends Logging { def deriveJSON[A]: JSON[A] = macro JSONMacros.deriveJSON_impl[A] def deriveSingletonJSON[A]: JSON[A] = macro JSONMacros.deriveSingletonJSON_impl[A] + def deriveToJSON[A]: ToJSON[A] = macro JSONMacros.deriveToJSON_impl[A] + def deriveFromJSON[A]: FromJSON[A] = macro JSONMacros.deriveFromJSON_impl[A] + private def JSONofToAndFrom[A](toJSON: ToJSON[A], fromJSON: FromJSON[A]): JSON[A] = { new JSON[A] { @@ -407,6 +410,8 @@ package object generic extends Logging { new JSON[T] with TypeSelectorContainer { override def typeSelectors: List[TypeSelector[_]] = allSelectors + override def subTypeNames: List[String] = allSelectors.map(_.typeValue) + def read(jval: JValue): ValidatedNel[JSONError, T] = fromJSON.read(jval) def write(t: T): JValue = toJSON.write(t) diff --git a/json/json-derivation/src/test/scala/io/sphere/json/DeriveJSONCompatibilitySpec.scala b/json/json-derivation/src/test/scala/io/sphere/json/DeriveJSONCompatibilitySpec.scala new file mode 100644 index 00000000..9284d7b0 --- /dev/null +++ b/json/json-derivation/src/test/scala/io/sphere/json/DeriveJSONCompatibilitySpec.scala @@ -0,0 +1,70 @@ +package io.sphere.json + +import java.util.UUID +import org.scalacheck.{Arbitrary, Gen} +import org.scalatest.matchers.must.Matchers +import org.scalatest.wordspec.AnyWordSpec +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks + +import io.sphere.json.generic.deriveJSON +import io.sphere.json.generic.jsonProduct + +class DeriveJSONCompatibilitySpec extends AnyWordSpec with Matchers with ScalaCheckPropertyChecks { + + "jsonProduct must work the same as deriveJSON for case classes" in { + + import DeriveJSONCompatibilitySpec._ + + val deriveSyntax: JSON[ClassOfManyTypes] = { + implicit val nestedF: JSON[NestedClass] = deriveJSON + deriveJSON + } + val jsonProductSyntax: JSON[ClassOfManyTypes] = { + implicit val nestedF: JSON[NestedClass] = jsonProduct(NestedClass.apply _) + jsonProduct(ClassOfManyTypes.apply _) + } + + forAll { (x: ClassOfManyTypes) => + val jsonJP = jsonProductSyntax.write(x) + val jsonD = deriveSyntax.write(x) + + jsonJP must be(jsonD) + + jsonProductSyntax.read(jsonD).getOrElse(null) must be(x) + deriveSyntax.read(jsonJP).getOrElse(null) must be(x) + } + + } + +} + +object DeriveJSONCompatibilitySpec { + + case class NestedClass(id: UUID, str2: String, int2: Int) + + case class ClassOfManyTypes( + str: String, + int: Int, + long: Long, + list: List[Int], + mapOfNested: Map[String, NestedClass] + ) + + implicit val userArbitrary: Arbitrary[NestedClass] = Arbitrary { + for { + id <- Gen.const(UUID.randomUUID()) + firstName <- Gen.alphaStr.suchThat(_.nonEmpty) + age <- Gen.chooseNum(1, 120) + } yield NestedClass(id, firstName, age) + } + + implicit val cmtArbitrary: Arbitrary[ClassOfManyTypes] = Arbitrary { + for { + str <- Gen.alphaStr.suchThat(_.nonEmpty) + int <- Arbitrary.arbitrary[Int] + long <- Arbitrary.arbitrary[Long] + list <- Gen.listOf(Arbitrary.arbitrary[Int]) + map <- Gen.mapOf(Gen.zip(Gen.alphaStr.suchThat(_.nonEmpty), Arbitrary.arbitrary[NestedClass])) + } yield ClassOfManyTypes(str, int, long, list, map) + } +} diff --git a/json/json-derivation/src/test/scala/io/sphere/json/JSONEmbeddedSpec.scala b/json/json-derivation/src/test/scala/io/sphere/json/JSONEmbeddedSpec.scala index 459a8417..7445ae57 100644 --- a/json/json-derivation/src/test/scala/io/sphere/json/JSONEmbeddedSpec.scala +++ b/json/json-derivation/src/test/scala/io/sphere/json/JSONEmbeddedSpec.scala @@ -10,29 +10,29 @@ object JSONEmbeddedSpec { case class Embedded(value1: String, value2: Int) object Embedded { - implicit val json: JSON[Embedded] = jsonProduct(apply _) + implicit val json: JSON[Embedded] = deriveJSON } case class Test1(name: String, @JSONEmbedded embedded: Embedded) object Test1 { - implicit val json: JSON[Test1] = jsonProduct(apply _) + implicit val json: JSON[Test1] = deriveJSON } case class Test2(name: String, @JSONEmbedded embedded: Option[Embedded] = None) object Test2 { - implicit val json: JSON[Test2] = jsonProduct(apply _) + implicit val json: JSON[Test2] = deriveJSON } case class SubTest4(@JSONEmbedded embedded: Embedded) object SubTest4 { - implicit val json: JSON[SubTest4] = jsonProduct(apply _) + implicit val json: JSON[SubTest4] = deriveJSON } case class Test4(subField: Option[SubTest4] = None) object Test4 { - implicit val json: JSON[Test4] = jsonProduct(apply _) + implicit val json: JSON[Test4] = deriveJSON } } diff --git a/json/json-derivation/src/test/scala/io/sphere/json/JSONSpec.scala b/json/json-derivation/src/test/scala/io/sphere/json/JSONSpec.scala index 325000d9..7a55d96a 100644 --- a/json/json-derivation/src/test/scala/io/sphere/json/JSONSpec.scala +++ b/json/json-derivation/src/test/scala/io/sphere/json/JSONSpec.scala @@ -172,13 +172,14 @@ class JSONSpec extends AnyFunSpec with Matchers { it("must provide derived instances for sum types with a mix of case class / object") { implicit val mixedJSON = deriveJSON[Mixed] + List(SingletonMixed, RecordMixed(1)).foreach { m: Mixed => fromJSON[Mixed](toJSON(m)) must equal(Valid(m)) } } it("must provide derived instances for scala.Enumeration") { - implicit val scalaEnumJSON = deriveJSON[ScalaEnum.Value] + implicit val scalaEnumJSON: JSON[JSONSpec.ScalaEnum.Value] = jsonEnum(ScalaEnum) ScalaEnum.values.foreach { v => val json = s"""[${toJSON(v)}]""" withClue(json) { @@ -188,7 +189,7 @@ class JSONSpec extends AnyFunSpec with Matchers { } it("must handle subclasses correctly in `jsonTypeSwitch`") { - implicit val jsonImpl = TestSubjectBase.json + implicit val jsonImpl: JSON[TestSubjectBase] = TestSubjectBase.json val testSubjects = List[TestSubjectBase]( TestSubjectConcrete1("testSubject1"), @@ -211,24 +212,24 @@ class JSONSpec extends AnyFunSpec with Matchers { describe("ToJSON and FromJSON") { it("must provide derived JSON instances for sum types") { // ToJSON - implicit val birdToJSON = toJsonProduct(Bird.apply _) - implicit val dogToJSON = toJsonProduct(Dog.apply _) - implicit val catToJSON = toJsonProduct(Cat.apply _) + implicit val birdToJSON: ToJSON[Bird] = deriveToJSON + implicit val dogToJSON: ToJSON[Dog] = deriveToJSON + implicit val catToJSON: ToJSON[Cat] = deriveToJSON implicit val animalToJSON = toJsonTypeSwitch[Animal, Bird, Dog, Cat](Nil) // FromJSON - implicit val birdFromJSON = fromJsonProduct(Bird.apply _) - implicit val dogFromJSON = fromJsonProduct(Dog.apply _) - implicit val catFromJSON = fromJsonProduct(Cat.apply _) + implicit val birdFromJSON: FromJSON[Bird] = deriveFromJSON + implicit val dogFromJSON: FromJSON[Dog] = deriveFromJSON + implicit val catFromJSON: FromJSON[Cat] = deriveFromJSON implicit val animalFromJSON = fromJsonTypeSwitch[Animal, Bird, Dog, Cat](Nil) - List(Bird("Peewee"), Dog("Hasso"), Cat("Felidae")).foreach { a: Animal => + List(Bird("Peewee"), Dog("Hasso"), Cat("Felidae")).foreach { (a: Animal) => fromJSON[Animal](toJSON(a)) must equal(Valid(a)) } } it("must provide derived instances for product types with concrete type parameters") { - implicit val aToJSON = toJsonProduct(GenericA.apply[String] _) - implicit val aFromJSON = fromJsonProduct(GenericA.apply[String] _) + implicit val aToJSON: ToJSON[GenericA[String]] = deriveToJSON + implicit val aFromJSON: FromJSON[GenericA[String]] = deriveFromJSON val a = GenericA("hello") fromJSON[GenericA[String]](toJSON(a)) must equal(Valid(a)) } @@ -265,12 +266,12 @@ class JSONSpec extends AnyFunSpec with Matchers { it("must provide derived instances for sum types with a mix of case class / object") { // ToJSON - implicit val toSingleJSON = toJsonProduct0(SingletonMixed) - implicit val toRecordJSON = toJsonProduct(RecordMixed.apply _) + implicit val toSingleJSON: ToJSON[JSONSpec.SingletonMixed.type] = deriveToJSON + implicit val toRecordJSON: ToJSON[RecordMixed] = deriveToJSON implicit val toMixedJSON = toJsonTypeSwitch[Mixed, SingletonMixed.type, RecordMixed](Nil) // FromJSON - implicit val fromSingleJSON = fromJsonProduct0(SingletonMixed) - implicit val fromRecordJSON = fromJsonProduct(RecordMixed.apply _) + implicit val fromSingleJSON: FromJSON[JSONSpec.SingletonMixed.type] = deriveFromJSON + implicit val fromRecordJSON: FromJSON[RecordMixed] = deriveFromJSON implicit val fromMixedJSON = fromJsonTypeSwitch[Mixed, SingletonMixed.type, RecordMixed](Nil) List(SingletonMixed, RecordMixed(1)).foreach { m: Mixed => fromJSON[Mixed](toJSON(m)) must equal(Valid(m)) @@ -290,10 +291,10 @@ class JSONSpec extends AnyFunSpec with Matchers { it("must handle subclasses correctly in `jsonTypeSwitch`") { // ToJSON - implicit val to1 = toJsonProduct(TestSubjectConcrete1.apply _) - implicit val to2 = toJsonProduct(TestSubjectConcrete2.apply _) - implicit val to3 = toJsonProduct(TestSubjectConcrete3.apply _) - implicit val to4 = toJsonProduct(TestSubjectConcrete4.apply _) + implicit val to1: ToJSON[TestSubjectConcrete1] = deriveToJSON + implicit val to2: ToJSON[TestSubjectConcrete2] = deriveToJSON + implicit val to3: ToJSON[TestSubjectConcrete3] = deriveToJSON + implicit val to4: ToJSON[TestSubjectConcrete4] = deriveToJSON implicit val toA = toJsonTypeSwitch[TestSubjectCategoryA, TestSubjectConcrete1, TestSubjectConcrete2](Nil) implicit val toB = @@ -302,10 +303,10 @@ class JSONSpec extends AnyFunSpec with Matchers { toJsonTypeSwitch[TestSubjectBase, TestSubjectCategoryA, TestSubjectCategoryB](Nil) // FromJSON - implicit val from1 = fromJsonProduct(TestSubjectConcrete1.apply _) - implicit val from2 = fromJsonProduct(TestSubjectConcrete2.apply _) - implicit val from3 = fromJsonProduct(TestSubjectConcrete3.apply _) - implicit val from4 = fromJsonProduct(TestSubjectConcrete4.apply _) + implicit val from1: FromJSON[TestSubjectConcrete1] = deriveFromJSON + implicit val from2: FromJSON[TestSubjectConcrete2] = deriveFromJSON + implicit val from3: FromJSON[TestSubjectConcrete3] = deriveFromJSON + implicit val from4: FromJSON[TestSubjectConcrete4] = deriveFromJSON implicit val fromA = fromJsonTypeSwitch[TestSubjectCategoryA, TestSubjectConcrete1, TestSubjectConcrete2](Nil) implicit val fromB = @@ -332,11 +333,11 @@ class JSONSpec extends AnyFunSpec with Matchers { it("must provide derived JSON instances for product types (case classes)") { import JSONSpec.{Milestone, Project} // ToJSON - implicit val milestoneToJSON = toJsonProduct(Milestone.apply _) - implicit val projectToJSON = toJsonProduct(Project.apply _) + implicit val milestoneToJSON: ToJSON[Milestone] = deriveToJSON + implicit val projectToJSON: ToJSON[Project] = deriveToJSON // FromJSON - implicit val milestoneFromJSON = fromJsonProduct(Milestone.apply _) - implicit val projectFromJSON = fromJsonProduct(Project.apply _) + implicit val milestoneFromJSON: FromJSON[Milestone] = deriveFromJSON + implicit val projectFromJSON: FromJSON[Project] = deriveFromJSON val proj = Project(42, "Linux", 7, Milestone("1.0") :: Milestone("2.0") :: Milestone("3.0") :: Nil) diff --git a/json/json-derivation/src/test/scala/io/sphere/json/OptionReaderSpec.scala b/json/json-derivation/src/test/scala/io/sphere/json/OptionReaderSpec.scala index affb805e..6535d8ac 100644 --- a/json/json-derivation/src/test/scala/io/sphere/json/OptionReaderSpec.scala +++ b/json/json-derivation/src/test/scala/io/sphere/json/OptionReaderSpec.scala @@ -11,23 +11,23 @@ object OptionReaderSpec { case class SimpleClass(value1: String, value2: Int) object SimpleClass { - implicit val json: JSON[SimpleClass] = jsonProduct(apply _) + implicit val json: JSON[SimpleClass] = deriveJSON } case class ComplexClass(name: String, simpleClass: Option[SimpleClass]) object ComplexClass { - implicit val json: JSON[ComplexClass] = jsonProduct(apply _) + implicit val json: JSON[ComplexClass] = deriveJSON } case class MapClass(id: Long, map: Option[Map[String, String]]) object MapClass { - implicit val json: JSON[MapClass] = jsonProduct(apply _) + implicit val json: JSON[MapClass] = deriveJSON } case class ListClass(id: Long, list: Option[List[String]]) object ListClass { - implicit val json: JSON[ListClass] = jsonProduct(apply _) + implicit val json: JSON[ListClass] = deriveJSON } } diff --git a/json/json-derivation/src/test/scala/io/sphere/json/generic/DefaultValuesSpec.scala b/json/json-derivation/src/test/scala/io/sphere/json/generic/DefaultValuesSpec.scala index dd81878b..116ba388 100644 --- a/json/json-derivation/src/test/scala/io/sphere/json/generic/DefaultValuesSpec.scala +++ b/json/json-derivation/src/test/scala/io/sphere/json/generic/DefaultValuesSpec.scala @@ -28,6 +28,6 @@ object DefaultValuesSpec { value4: Option[String] = Some("hi") ) object Test { - implicit val mongo: JSON[Test] = jsonProduct(apply _) + implicit val mongo: JSON[Test] = deriveJSON } } diff --git a/json/json-derivation/src/test/scala/io/sphere/json/generic/JSONKeySpec.scala b/json/json-derivation/src/test/scala/io/sphere/json/generic/JSONKeySpec.scala index 61a9add1..66bb9c5e 100644 --- a/json/json-derivation/src/test/scala/io/sphere/json/generic/JSONKeySpec.scala +++ b/json/json-derivation/src/test/scala/io/sphere/json/generic/JSONKeySpec.scala @@ -31,7 +31,7 @@ object JSONKeySpec { @JSONKey("new_sub_value_2") value2: String ) object SubTest { - implicit val mongo: JSON[SubTest] = jsonProduct(apply _) + implicit val mongo: JSON[SubTest] = deriveJSON } case class Test( @@ -40,6 +40,6 @@ object JSONKeySpec { @JSONEmbedded subTest: SubTest ) object Test { - implicit val mongo: JSON[Test] = jsonProduct(apply _) + implicit val mongo: JSON[Test] = deriveJSON } } diff --git a/json/json-derivation/src/test/scala/io/sphere/json/generic/JsonTypeHintFieldSpec.scala b/json/json-derivation/src/test/scala/io/sphere/json/generic/JsonTypeHintFieldSpec.scala index 41d60f94..62d7af94 100644 --- a/json/json-derivation/src/test/scala/io/sphere/json/generic/JsonTypeHintFieldSpec.scala +++ b/json/json-derivation/src/test/scala/io/sphere/json/generic/JsonTypeHintFieldSpec.scala @@ -52,12 +52,12 @@ object JsonTypeHintFieldSpec { case object Big extends PictureSize object PictureSize { - implicit val json: JSON[PictureSize] = deriveJSON[PictureSize] + implicit val json: JSON[PictureSize] = deriveJSON } case class UserWithPicture(userId: String, pictureSize: PictureSize, pictureUrl: String) object UserWithPicture { - implicit val json: JSON[UserWithPicture] = jsonProduct(apply _) + implicit val json: JSON[UserWithPicture] = deriveJSON } } diff --git a/json/json-derivation/src/test/scala/io/sphere/json/generic/SubTypeNameSpec.scala b/json/json-derivation/src/test/scala/io/sphere/json/generic/SubTypeNameSpec.scala new file mode 100644 index 00000000..2a2912ac --- /dev/null +++ b/json/json-derivation/src/test/scala/io/sphere/json/generic/SubTypeNameSpec.scala @@ -0,0 +1,45 @@ +package io.sphere.json.generic + +import io.sphere.json.JSON +import org.scalatest.matchers.must.Matchers +import org.scalatest.wordspec.AnyWordSpec + +class SubTypeNameSpec extends AnyWordSpec with Matchers { + import SubTypeNameSpec._ + + "JSON.subtypeNames" must { + + val subTypeNames = List("Obj1", "Obj2", "Class1", "Class2") + "return all subtypes of a trait when using deriveJSON" in { + val format: JSON[SuperType] = deriveJSON + + format.subTypeNames must be(subTypeNames) + + format.asInstanceOf[TypeSelectorContainer].typeSelectors.map(_.typeValue) must be( + subTypeNames) + } + + "return all subtypes of a trait when using jsonTypeSwitch" in { + implicit val obj1F: JSON[Obj1.type] = deriveJSON + implicit val objHF: JSON[ObjHidden.type] = deriveJSON + implicit val class1F: JSON[Class1] = deriveJSON + implicit val classhF: JSON[ClassHidden] = deriveJSON + + val format: JSON[SuperType] = + jsonTypeSwitch[SuperType, Obj1.type, ObjHidden.type, Class1, ClassHidden](Nil) + + format.subTypeNames must be(subTypeNames) + + format.asInstanceOf[TypeSelectorContainer].typeSelectors.map(_.typeValue) must be( + subTypeNames) + } + } +} + +object SubTypeNameSpec { + sealed trait SuperType + case object Obj1 extends SuperType + @JSONTypeHint("Obj2") case object ObjHidden extends SuperType + case class Class1(int: Int) extends SuperType + @JSONTypeHint("Class2") case class ClassHidden(int: Int) extends SuperType +} diff --git a/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/SerializationTest.scala b/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/SerializationTest.scala index ec281dba..b9c6d784 100644 --- a/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/SerializationTest.scala +++ b/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/SerializationTest.scala @@ -29,10 +29,7 @@ class SerializationTest extends AnyWordSpec with Matchers { } "generate a format that serializes optional fields with value None as BSON objects without that field" in { - val testFormat: MongoFormat[Something] = - io.sphere.mongo.generic.mongoProduct[Something, Option[Int], Int] { - (a: Option[Int], b: Int) => Something(a, b) - } + val testFormat: MongoFormat[Something] = io.sphere.mongo.generic.deriveMongoFormat val serializedObject = testFormat.toMongoValue(Something(None, 1)).asInstanceOf[DBObject] serializedObject.keySet().contains("b") must be(true) diff --git a/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/format/OptionMongoFormatSpec.scala b/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/format/OptionMongoFormatSpec.scala index daf324c9..f8485610 100644 --- a/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/format/OptionMongoFormatSpec.scala +++ b/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/format/OptionMongoFormatSpec.scala @@ -12,13 +12,13 @@ object OptionMongoFormatSpec { case class SimpleClass(value1: String, value2: Int) object SimpleClass { - implicit val mongo: MongoFormat[SimpleClass] = mongoProduct(apply _) + implicit val mongo: MongoFormat[SimpleClass] = deriveMongoFormat } case class ComplexClass(name: String, simpleClass: Option[SimpleClass]) object ComplexClass { - implicit val mongo: MongoFormat[ComplexClass] = mongoProduct(apply _) + implicit val mongo: MongoFormat[ComplexClass] = deriveMongoFormat } } diff --git a/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/generic/DefaultValuesSpec.scala b/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/generic/DefaultValuesSpec.scala index 2d016857..03e7dd2d 100644 --- a/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/generic/DefaultValuesSpec.scala +++ b/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/generic/DefaultValuesSpec.scala @@ -29,6 +29,6 @@ object DefaultValuesSpec { value4: Option[String] = Some("hi") ) object Test { - implicit val mongo: MongoFormat[Test] = mongoProduct(apply _) + implicit val mongo: MongoFormat[Test] = deriveMongoFormat } } diff --git a/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/generic/DeriveMongoformatSpec.scala b/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/generic/DeriveMongoformatSpec.scala index fcf3e559..ebf1c7a6 100644 --- a/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/generic/DeriveMongoformatSpec.scala +++ b/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/generic/DeriveMongoformatSpec.scala @@ -125,7 +125,7 @@ object DeriveMongoformatSpec { access: Option[Access] = None) object UserWithPicture { - implicit val mongo: MongoFormat[UserWithPicture] = mongoProduct(apply _) + implicit val mongo: MongoFormat[UserWithPicture] = deriveMongoFormat } sealed trait SealedParent diff --git a/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/generic/MongoEmbeddedSpec.scala b/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/generic/MongoEmbeddedSpec.scala index 1483da9d..12d1b52a 100644 --- a/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/generic/MongoEmbeddedSpec.scala +++ b/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/generic/MongoEmbeddedSpec.scala @@ -13,19 +13,19 @@ object MongoEmbeddedSpec { case class Embedded(value1: String, @MongoKey("_value2") value2: Int) object Embedded { - implicit val mongo: MongoFormat[Embedded] = mongoProduct(apply _) + implicit val mongo: MongoFormat[Embedded] = deriveMongoFormat } case class Test1(name: String, @MongoEmbedded embedded: Embedded) object Test1 { - implicit val mongo: MongoFormat[Test1] = mongoProduct(apply _) + implicit val mongo: MongoFormat[Test1] = deriveMongoFormat } case class Test2(name: String, @MongoEmbedded embedded: Option[Embedded] = None) object Test2 { - implicit val mongo: MongoFormat[Test2] = mongoProduct(apply _) + implicit val mongo: MongoFormat[Test2] = deriveMongoFormat } case class Test3( @@ -33,17 +33,17 @@ object MongoEmbeddedSpec { @MongoEmbedded embedded: Option[Embedded] = None) object Test3 { - implicit val mongo: MongoFormat[Test3] = mongoProduct(apply _) + implicit val mongo: MongoFormat[Test3] = deriveMongoFormat } case class SubTest4(@MongoEmbedded embedded: Embedded) object SubTest4 { - implicit val mongo: MongoFormat[SubTest4] = mongoProduct(apply _) + implicit val mongo: MongoFormat[SubTest4] = deriveMongoFormat } case class Test4(subField: Option[SubTest4] = None) object Test4 { - implicit val mongo: MongoFormat[Test4] = mongoProduct(apply _) + implicit val mongo: MongoFormat[Test4] = deriveMongoFormat } } diff --git a/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/generic/MongoKeySpec.scala b/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/generic/MongoKeySpec.scala index 2f001de0..3392124b 100644 --- a/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/generic/MongoKeySpec.scala +++ b/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/generic/MongoKeySpec.scala @@ -34,7 +34,7 @@ object MongoKeySpec { @MongoKey("new_sub_value_2") value2: String ) object SubTest { - implicit val mongo: MongoFormat[SubTest] = mongoProduct(apply _) + implicit val mongo: MongoFormat[SubTest] = deriveMongoFormat } case class Test( @@ -43,6 +43,6 @@ object MongoKeySpec { @MongoEmbedded subTest: SubTest ) object Test { - implicit val mongo: MongoFormat[Test] = mongoProduct(apply _) + implicit val mongo: MongoFormat[Test] = deriveMongoFormat } } diff --git a/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/generic/MongoTypeHintFieldWithAbstractClassSpec.scala b/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/generic/MongoTypeHintFieldWithAbstractClassSpec.scala index e78b98c5..ffc923eb 100644 --- a/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/generic/MongoTypeHintFieldWithAbstractClassSpec.scala +++ b/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/generic/MongoTypeHintFieldWithAbstractClassSpec.scala @@ -52,6 +52,6 @@ object MongoTypeHintFieldWithAbstractClassSpec { case class UserWithPicture(userId: String, pictureSize: PictureSize, pictureUrl: String) object UserWithPicture { - implicit val mongo: MongoFormat[UserWithPicture] = mongoProduct(apply _) + implicit val mongo: MongoFormat[UserWithPicture] = deriveMongoFormat } } diff --git a/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/generic/MongoTypeHintFieldWithSealedTraitSpec.scala b/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/generic/MongoTypeHintFieldWithSealedTraitSpec.scala index 558906b3..ef91fdd1 100644 --- a/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/generic/MongoTypeHintFieldWithSealedTraitSpec.scala +++ b/mongo/mongo-derivation/src/test/scala/io/sphere/mongo/generic/MongoTypeHintFieldWithSealedTraitSpec.scala @@ -57,6 +57,6 @@ object MongoTypeHintFieldWithSealedTraitSpec { case class UserWithPicture(userId: String, pictureSize: PictureSize, pictureUrl: String) object UserWithPicture { - implicit val mongo: MongoFormat[UserWithPicture] = mongoProduct(apply _) + implicit val mongo: MongoFormat[UserWithPicture] = deriveMongoFormat } }