Skip to content

fromJSON + toJSON are not Idempotent #32

@J-Moravec

Description

@J-Moravec

The operation fromJSON followed by toJSON should semantically modify the json. I.e., these two chained should be content indempotent / symetric.

This is currently not the case, rjson doesn't distinguishes between scalars and single element arrays, it also converts empty objects into arrays.

library("rjson")

# json as a multiline string
# validated with https://jsonlint.com/
json = '{
    "object": {
        "name": "value"
    },
    "object_empty": {},
    "single_element": 1,
    "array_one": [
        1
    ],
    "array_two": [
        1,
        2
    ],
    "array_empty": []
}'

obj = rjson::fromJSON(json) |> rjson::toJSON(4)

# We can't compare with identical due to changes in formatting:
cat(obj)
{
    "object":{
        "name":"value"
    },
    "object_empty":[

    ],
    "single_element":    1,
    "array_one":    1,
    "array_two":[
        1,
        2
    ],
    "array_empty":[

    ]
}

The above example demonstrate two big issues resulting in change of type. This is very problematic with any typed system that does distinguish between scalar and vectors/arrays (unlike R :/)

  1. "object_empty" -- previously empty object {} is converted to empty array -> TYPE CHANGE
  2. "array_one" -- previously a single element array is turned into a scalar -> TYPE CHANGE

Note that jsonlite can with some work be forced to follow the rules:

jsonlite::fromJSON(json, simplifyVector = FALSE) |>
  jsonlite::toJSON(pretty = TRUE, auto_unbox = TRUE) |>
  cat()

Its stupid that one has to go to such length to do so but at least, it works.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions