Skip to content

Commit 039275f

Browse files
committed
reformatting
1 parent eba8c75 commit 039275f

File tree

11 files changed

+351
-0
lines changed

11 files changed

+351
-0
lines changed

build.sbt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,16 @@ lazy val scala_libraries = (project in file("scala-libraries"))
445445
"org.elasticmq" %% "elasticmq-rest-sqs" % "1.6.7",
446446
"software.amazon.awssdk" % "sqs" % "2.27.10"
447447
),
448+
Defaults.itSettings
449+
)
450+
451+
lazy val scala_libraries_2 = (project in file("scala-libraries-2"))
452+
.configs(IntegrationTest)
453+
.settings(
454+
name := "scala-libraries-2",
455+
scalaVersion := scala3Version,
456+
libraryDependencies ++= scalaTestDeps
457+
.map(_.withConfigurations(Some("it,test"))),
448458
libraryDependencies += "io.scalaland" %% "chimney" % "1.4.0",
449459
Defaults.itSettings
450460
)

scala-libraries-2/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
## Relevant Articles:
2+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.baeldung.circe
2+
3+
import com.baeldung.circe.JSONConversions.{stringJson, invalidStringJson}
4+
import io.circe.parser.parse
5+
import org.scalatest.flatspec.AnyFlatSpec
6+
import org.scalatest.matchers.should
7+
8+
class JSONConversionsUnitTest extends AnyFlatSpec with should.Matchers {
9+
"Convert Json String" should "successfully" in {
10+
val parseResult = parse(stringJson)
11+
assert(parseResult.isRight)
12+
}
13+
14+
"Convert Json String" should "fail return a Json" in {
15+
val parseResult = parse(invalidStringJson)
16+
assert(parseResult.isLeft)
17+
}
18+
}
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
package com.baeldung.scala.circe
2+
3+
import org.scalatest.flatspec.AnyFlatSpec
4+
import org.scalatest.matchers.should
5+
6+
class CirceUnitTest extends AnyFlatSpec with should.Matchers {
7+
8+
val jsonString =
9+
"""{
10+
| "textField" : "textContent",
11+
| "numericField" : 123,
12+
| "booleanField" : true,
13+
| "nestedObject" : {
14+
| "arrayField" : [
15+
| 1,
16+
| 2,
17+
| 3
18+
| ]
19+
| }
20+
|}""".stripMargin
21+
22+
val jsonStringWithMissingFields =
23+
"""{
24+
| "textField" : "textContent",
25+
| "nestedObject" : {
26+
| "arrayField" : null
27+
| }
28+
|}""".stripMargin
29+
30+
"Circe" should "validate a valid JSON string" in {
31+
import io.circe._, io.circe.parser._
32+
33+
val parseResult: Either[ParsingFailure, Json] = parse(jsonString)
34+
35+
parseResult match {
36+
case Left(parsingError) =>
37+
throw new IllegalArgumentException(
38+
s"Invalid JSON object: ${parsingError.message}"
39+
)
40+
case Right(json) =>
41+
val numbers = json \\ "numericField"
42+
val firstNumber: Option[Option[JsonNumber]] = numbers.collectFirst {
43+
case field => field.asNumber
44+
}
45+
46+
val singleOption: Option[Int] = firstNumber.flatten.flatMap(_.toInt)
47+
48+
singleOption shouldEqual Some[Int](123)
49+
}
50+
}
51+
52+
it should "convert JSON into object using converters and back to original string" in {
53+
import io.circe._, io.circe.generic.semiauto._, io.circe.parser._,
54+
io.circe.syntax._
55+
56+
case class Nested(arrayField: List[Int])
57+
58+
case class OurJson(
59+
textField: String,
60+
numericField: Int,
61+
booleanField: Boolean,
62+
nestedObject: Nested
63+
)
64+
65+
implicit val nestedDecoder: Decoder[Nested] = deriveDecoder[Nested]
66+
implicit val jsonDecoder: Decoder[OurJson] = deriveDecoder[OurJson]
67+
68+
decode[OurJson](jsonString) shouldEqual Right(
69+
OurJson("textContent", 123, true, Nested(List(1, 2, 3)))
70+
)
71+
72+
val decoded = decode[OurJson](jsonString)
73+
74+
implicit val nestedEncoder: Encoder[Nested] = deriveEncoder[Nested]
75+
implicit val jsonEncoder: Encoder[OurJson] = deriveEncoder[OurJson]
76+
77+
decoded match {
78+
case Right(decodedJson) =>
79+
val jsonObject: Json = decodedJson.asJson
80+
jsonObject.spaces2 shouldEqual jsonString
81+
}
82+
}
83+
84+
it should "decode a JSON with missing fields" in {
85+
import io.circe._, io.circe.generic.semiauto._, io.circe.parser._
86+
87+
val jsonStringWithMissingFields =
88+
"""{
89+
| "textField" : "textContent",
90+
| "nestedObject" : {
91+
| "arrayField" : null
92+
| }
93+
|}""".stripMargin
94+
95+
case class Nested(arrayField: Option[List[Int]])
96+
97+
case class OurJson(
98+
textField: String,
99+
numericField: Option[Int],
100+
booleanField: Option[Boolean],
101+
nestedObject: Nested
102+
)
103+
104+
implicit val nestedDecoder: Decoder[Nested] = deriveDecoder[Nested]
105+
implicit val jsonDecoder: Decoder[OurJson] = deriveDecoder[OurJson]
106+
107+
decode[OurJson](jsonStringWithMissingFields) shouldEqual Right(
108+
OurJson("textContent", None, None, Nested(None))
109+
)
110+
}
111+
112+
it should "decode a JSON with missing fields using a custom decoder" in {
113+
import io.circe._, io.circe.generic.semiauto._, io.circe.parser._
114+
115+
case class Nested(arrayField: List[Int])
116+
117+
case class OurJson(
118+
textField: String,
119+
numericField: Option[Int],
120+
booleanField: Option[Boolean],
121+
nestedObject: Nested
122+
)
123+
124+
implicit val decodeNested: Decoder[Nested] = (c: HCursor) =>
125+
for {
126+
arrayField <- c.downField("arrayField").as[Option[List[Int]]]
127+
} yield {
128+
val flattenedArray = arrayField.getOrElse(Nil)
129+
Nested(flattenedArray)
130+
}
131+
132+
implicit val jsonDecoder: Decoder[OurJson] = deriveDecoder[OurJson]
133+
134+
decode[OurJson](jsonStringWithMissingFields) shouldEqual Right(
135+
OurJson("textContent", None, None, Nested(Nil))
136+
)
137+
138+
val jsonStringWithArray =
139+
"""{
140+
| "textField" : "textContent",
141+
| "nestedObject" : {
142+
| "arrayField" : [1, 2]
143+
| }
144+
|}""".stripMargin
145+
146+
decode[OurJson](jsonStringWithArray) shouldEqual Right(
147+
OurJson("textContent", None, None, Nested(List(1, 2)))
148+
)
149+
}
150+
151+
it should "use automatic decoder derivation" in {
152+
import io.circe.generic.auto._, io.circe.parser
153+
154+
case class Nested(arrayField: List[Int])
155+
156+
case class OurJson(
157+
textField: String,
158+
numericField: Int,
159+
booleanField: Boolean,
160+
nestedObject: Nested
161+
)
162+
163+
parser.decode[OurJson](jsonString) shouldEqual Right(
164+
OurJson("textContent", 123, true, Nested(List(1, 2, 3)))
165+
)
166+
}
167+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package com.baeldung.scala.circe
2+
3+
import org.scalatest.flatspec.AnyFlatSpec
4+
import org.scalatest.matchers.should
5+
import io.circe._
6+
import io.circe.generic.semiauto._
7+
import io.circe.parser._
8+
9+
class CustomDecoderUnitTest extends AnyFlatSpec with should.Matchers {
10+
11+
val jsonStringWithNullArray =
12+
"""{
13+
| "textField" : "textContent",
14+
| "nestedObject" : {
15+
| "arrayField" : null
16+
| }
17+
|}""".stripMargin
18+
19+
val jsonStringWithMissingArray =
20+
"""{
21+
| "textField" : "textContent",
22+
| "nestedObject" : {
23+
| }
24+
|}""".stripMargin
25+
26+
val jsonStringWithArray =
27+
"""{
28+
| "textField" : "textContent",
29+
| "nestedObject" : {
30+
| "arrayField" : [1, 2]
31+
| }
32+
|}""".stripMargin
33+
34+
val jsonStringWithEmptyArray =
35+
"""{
36+
| "textField" : "textContent",
37+
| "nestedObject" : {
38+
| "arrayField" : []
39+
| }
40+
|}""".stripMargin
41+
42+
case class Nested(arrayField: List[Int])
43+
44+
case class OurJson(
45+
textField: String,
46+
numericField: Option[Int],
47+
booleanField: Option[Boolean],
48+
nestedObject: Nested
49+
)
50+
51+
implicit val decodeNested: Decoder[Nested] = (c: HCursor) =>
52+
for {
53+
arrayField <- c.downField("arrayField").as[Option[List[Int]]]
54+
} yield {
55+
val flattenedArray = arrayField.getOrElse(Nil)
56+
Nested(flattenedArray)
57+
}
58+
59+
implicit val jsonDecoder: Decoder[OurJson] = deriveDecoder[OurJson]
60+
61+
"A custom decoder" should "decode a JSON with a null array value" in {
62+
decode[OurJson](jsonStringWithNullArray) shouldEqual Right(
63+
OurJson("textContent", None, None, Nested(Nil))
64+
)
65+
}
66+
67+
it should "decode a JSON with a missing field" in {
68+
decode[OurJson](jsonStringWithMissingArray) shouldEqual Right(
69+
OurJson("textContent", None, None, Nested(Nil))
70+
)
71+
}
72+
73+
it should "decode a JSON with an existing array value" in {
74+
decode[OurJson](jsonStringWithArray) shouldEqual Right(
75+
OurJson("textContent", None, None, Nested(List(1, 2)))
76+
)
77+
}
78+
79+
it should "decode a JSON with an empty array" in {
80+
decode[OurJson](jsonStringWithEmptyArray) shouldEqual Right(
81+
OurJson("textContent", None, None, Nested(Nil))
82+
)
83+
}
84+
}

0 commit comments

Comments
 (0)