Unconstant Conjunction A personal blog

A Note on Migrating Packages from rjson to jsonlite

Recently I was working on an R package that had historically used both rjson and jsonlite to serialize R objects to JSON (before sending it off to an API). In this case we wanted to remove the rjson depdency, which was only used in a few places.

The most noticable hiccup I encountered while porting the code was during encoding of parameter lists generated in R, which looked something like

params <- list(key1 = "param", key2 = NULL,
               key3 = c("paired", "params"))

In this case, rjson produced exactly what our API was looking for:

cat(rjson::toJSON(params))
#> {"key1":"param","key2":null,"key3":["paired","params"]}

But by default the jsonlite package will behave very differently:

jsonlite::toJSON(params)
#> {"key1":["param"],"key2":{},"key3":["paired","params"]}

(That is, the NULL has been converted to an empty dictionary and the key1 parameter has been turned into a one-element array.)

Fortunately, jsonlite is quite configurable. Vectors of a single element can be converted into bare values by passing the auto_unbox parameter to toJSON() (or handled individually with unbox()), and handling of NULL values can be customized with the null paramter.

To get the jsonlite equivalent to the rjson output above, we used

jsonlite::toJSON(params, auto_unbox = TRUE, null = "null")
#> {"key1":"param","key2":null,"key3":["paired","params"]}

During the transition, I ran a number of tests to ensure that the conversions were equivalent. Since jsonlite produces an object of class "json", you’ll need to coerce to character to make things like all.equal() work correctly:

a <- rjson::toJSON(params)
b <- jsonlite::toJSON(params, auto_unbox = TRUE, null = "null")

all.equal(a, b)
#> [1] "Attributes: < target is NULL, current is list >"
#> [2] "target is character, current is json"
all.equal(a, as.character(b))
#> [1] TRUE

Technical merits of each respective package aside, I think it’s likely that some existing rjson code will migrate to jsonlite in the future. Hopefully this post helps make that process a smooth one.

comments powered by Disqus