Unbox first level of options when serializing JSON #598
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Fixes #528
This PR makes
Option[T]
s serialize tonull
or unboxedt
s by default. Together with the default configuration ofserializeDefaults = false
, this allowsNone
fields oncase class
es to be omitted when serializingcase class
es. Even withserializeDefaults = true
, it still serializesOption[T]
asnull
or unboxedt
. Either way is much more in line with standard REST API and JSON schema practices than the current serialization ofOption[T]
as zero-or-one-element-arrays[]
or[t]
None
[]
null
(or nothing, if acase class
field withserializeDefaults = false
Some(1)
[1]
1
Some(None)
[[]]
[null]
Some(Some(1))
[[1]]
[1]
Despite the convenience, this does mean that there are certain data structures that do not get round tripped. e.g. a field
null: Option[T]
would get serialized tonull
, and deserialized asNone
. This is a tradeoff, but given the rarity ofnull
s in Scala codebases, and the intuitive expectations of howOption
s should behave, it seems a reasonable tradeoff.This PR does make an effort to support nested options:
Some(None)
is serialized as[null]
, whileSome(Some(t))
is serialized as[t]
. This manual boxing allows nestedOption
s to be preserved during round-trip read/write, rather than being flattened out to a single top-levelNone
. These nested options typically do not appear in REST APIs or JSON schemas, and so the choice to preserve round-trip-ability should not affect compatibility with public APIsThis is a breaking change that will need to go into uPickle 4.x. For backwards compatibility, and for migration purposes, the new serialization format is controlled under a flag
optionsAsNulls = true
. Users who really need the full round-trip preservation of Scala data structures, or who want to preserve compatibility with existing systems, can create a custom config withoptionsAsNulls = false
. Given the change in the serialization format, I haven't found a way to make uPickle read both old and new formats during the transition, but users can continue to use uPickle 4.x withoptionsAsNulls = false
indefinitely if they want to preserve compatibility with the old serialization formatFor users that want to enable
serializeDefaults = true
, we should be able to allowserializeDefaults
to be configurable on a per-field basis to allow it to be disabled just for the fields typed asOption
s, to continue eliding them while serializing other default values. Doing that can be done as a follow up