Skip to content

circe 0.3.0

Compare
Choose a tag to compare
@travisbrown travisbrown released this 14 Feb 00:59
· 2925 commits to series/0.14.x since this release

This release again represents a change of plans—instead of waiting for Shapeless 2.3.0 and ongoing related work in #164, we've decided that it makes sense to get a stable release published before those changes happen.

0.3.0 is likely to be a relatively short-lived release, since the current plan is to release 0.4.0 as soon as possible after Shapeless 2.3.0 is out and configurable generic derivation is ready.

New modules

This release introduces a number of new modules. Two of these are near (or at) the root of the dependency tree and represent a refactoring of core functionality:

  • circe-numbers is a zero-dependency module that supports more responsible representation of JSON numbers (see #189 for discussion). circe-core now depends on circe-numbers.
  • circe-scalajs provides a few functions designed to make Scala.js interoperability more convenient.

The rest of the new modules provide more experimental new functionality or interoperability with other libraries:

circe-parse has also been renamed circe-parser, but its role is unchanged.

Improved support (and decoders) for JSON numbers

The most substantial changes in behavior since 0.2 are related to the decoding of JSON numbers. One serious bug inherited from Argonaut has been fixed (it's no longer possible for user input to result in extremely computationally expensive operations on BigDecimal values), it's no longer possible for numeric input to result in runtime exceptions, and a number of small changes have been made to the behavior of the integral decoders. For example, the following now fails instead of returning 32767 (#83):

io.circe.jawn.decode[Short]("32768")

And the following fails instead of returning 10 (#83):

io.circe.jawn.decode[Int]("10.999")

The decoders for Double and Float also now follow the integral decoders in attempting to parse a JSON string:

scala> io.circe.jawn.decode[Double]("\"0.1\"")
res0: cats.data.Xor[io.circe.Error,Double] = Right(0.1)

See #189 and this blog post for more details.

Accumulating decoders

The idea is introduced in this blog post: it's now possible to transform a Decoder[A] into a new type AccumulatingDecoder[A] that accumulates errors whenever possible (assuming the original Decoder was defined in such a way as to support this). The behavior for ordinary decoders is completely unchanged, but it's now possible to do the following, for example:

import io.circe._, io.circe.generic.auto._

case class Foo(i: Int, s: String)

Decoder[Foo].accumulating(Json.empty.hcursor)

And get both errors instead of just the first.

Other changes

  • Decoder now has prepare and emap methods for transforming incoming JSON and successful results (#123).
  • Json now has a deepMerge method (#172).
  • It's now possible to replay history (in the form of a list of operations) against a cursor (#135).
  • A bug was fixed for Json's hashCode (#142).
  • circe now depends on Cats 0.4.1 and Scala.js 0.6.7 (instead of 0.2.0 and 0.6.5), but these updates have little impact on the public API.

Deprecations

  • &&& and ||| on Decoder (and ||| on ACursor) are now deprecated in favor of and and or.
  • + and - on JsonObject are being replaced by add and remove.

The decoder and encoder methods on io.circe.generic.semiauto.DerivationHelper are also now deprecated. Instead of the following:

import io.circe._, io.circe.generic.semiauto._

implicit val fooDecoder: Decoder[Foo] = deriveFor[Foo].decoder
implicit val fooEncoder: Encoder[Foo] = deriveFor[Foo].encoder

You'd now write:

import io.circe._, io.circe.generic.semiauto._

implicit val fooDecoder: Decoder[Foo] = deriveDecoder[Foo]
implicit val fooEncoder: Encoder[Foo] = deriveEncoder[Foo]

Or simply:

import io.circe._, io.circe.generic.semiauto._

implicit val fooDecoder: Decoder[Foo] = deriveDecoder
implicit val fooEncoder: Encoder[Foo] = deriveEncoder

All of the deprecated methods will be removed in 0.4.0.

Known issues

  • Jawn currently accepts -.1 as a JSON number, and circe represents it as a null JSON value. This means that the following will result in NaN, not -0.1 (the behavior in 0.2) or a decoding failure:

    io.circe.jawn.decode[Double]("-.1")
  • The parsing support provided by Scala.js in circe-parser is subject to the limitations of JavaScript's JSON parsing and will lose precision for values that can't be represented exactly as a double precision floating point number. (This is unchanged since 0.2.)

Contributors

Thanks to the twelve people who contributed code and documentation to this release, and to the many, many others who filed issues or offered feedback on Gitter.