Circe: Should a string `"""{"foo": "1.000"}"""` not be parsed `Some(1.0)` with `_.downField("foo").as[Option[Float]]`?

Created on 23 Aug 2018  路  3Comments  路  Source: circe/circe

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 !

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 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.)

All 3 comments

馃悤

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:

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dwijnand picture dwijnand  路  5Comments

danbills picture danbills  路  5Comments

Nr18 picture Nr18  路  5Comments

jonas picture jonas  路  4Comments

calippo picture calippo  路  3Comments