-
Notifications
You must be signed in to change notification settings - Fork 7
Change the API to be compatible with the upcoming Scala-3 v… #665
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
853c542
0c76e4f
912dbe5
77e9cd6
2b1d9d5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
``` | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We cannot use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Enumerations have a fixed implementation, we don't need to "derive" anything, so I didn't add them to the scala-3 deriveJSON. The code is simpler this way. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As we have |
||
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) | ||
|
Uh oh!
There was an error while loading. Please reload this page.