Hi 馃悤
I may have a question 馃槃.
Now, below code to be parsed to Right(Some(10))
import io.circe._
for {
json <- io.circe.parser.parse("""{"foo": "1.000"}""")
cursor = HCursor.fromJson(json)
} yield {
cursor.downField("foo").as[Option[Float]]
}
I'm a little unclear that it should be parsed successfully, or should not be.
In my opinion, it should return like Left(DecodingFailure("x(", cursor.history))),
because the json's "1.000" is not a Float (it is a string) 馃
How do you think about this?
Thanks !
馃悤
io.circe.parser.parse("""{"version": "1.000"}""").right.map(HCursor.fromJson(_)).right.map { _.downField("version").focus.map(_.isString) }
res4: scala.util.Either[io.circe.ParsingFailure,Option[Boolean]] = Right(Some(true))
scala> io.circe.parser.parse("""{"version": "1.000"}""").right.map(HCursor.fromJson(_)).right.map { _.downField("version").focus.map(_.isNumber) }
res6: scala.util.Either[io.circe.ParsingFailure,Option[Boolean]] = Right(Some(false))
scala> io.circe.parser.parse("""{"version": "1.000"}""").right.map(HCursor.fromJson(_)).right.map { _.downField("version").as[Option[String]] }
res7: scala.util.Either[io.circe.ParsingFailure,io.circe.Decoder.Result[Option[String]]] = Right(Right(Some(1.000)))
scala> io.circe.parser.parse("""{"version": "1.000"}""").right.map(HCursor.fromJson(_)).right.map { _.downField("version").as[Option[Float]] }
res8: scala.util.Either[io.circe.ParsingFailure,io.circe.Decoder.Result[Option[Float]]] = Right(Right(Some(1.0)))
@aiya000 @david-mcgillicuddy-ovo This behavior for numeric types is intentional, since it's pretty common to find numbers encoded as strings in the wild (Jackson's JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS, etc.).
If you want strict behavior, you can use a custom Decoder instance:
scala> import io.circe.Decoder, io.circe.generic.auto._, io.circe.jawn.decode
import io.circe.Decoder
import io.circe.generic.auto._
import io.circe.jawn.decode
scala> case class Foo(x: Double)
defined class Foo
scala> decode[Foo]("""{ "x": "1.0" }""")
res0: Either[io.circe.Error,Foo] = Right(Foo(1.0))
scala> implicit val strictlyDecodeDouble: Decoder[Double] =
| Decoder.decodeJsonNumber.flatMap(_ => Decoder.decodeDouble)
strictlyDecodeDouble: io.circe.Decoder[Double] = io.circe.Decoder$$anon$22@6c22b157
scala> decode[Foo]("""{ "x": "1.0" }""")
res1: Either[io.circe.Error,Foo] = Left(DecodingFailure(JsonNumber, List(DownField(x))))
(Note that this also fails on JSON null values, which by default are decoded as NaN.)
@travisbrown
Great! Thank you very much!
I got understanding :smiley:
I'll the custom Decoder instance :+1:
Most helpful comment
@aiya000 @david-mcgillicuddy-ovo This behavior for numeric types is intentional, since it's pretty common to find numbers encoded as strings in the wild (Jackson's
JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS, etc.).If you want strict behavior, you can use a custom
Decoderinstance:(Note that this also fails on JSON null values, which by default are decoded as
NaN.)