-
Notifications
You must be signed in to change notification settings - Fork 24
Deep Merging
The Json.with
method allows you to copy over the content of its argument into this
element. Types must match: you can merge an object with an object or an array with an array.
By default, the method does the simplest thing - if the element is a JSON object, it does a copy of all properties and if it is an array, it just appends all the elements of its argument. So, if we have:
Json dest = object("name", "John");
Json src = object("phone", "212-454-3490",
"address", object("street", "23 4th avenue",
"city", "New York"));
dest.with(src);
The dest
variable above will now contain also the phone number and address of John. However, note that the copy is not a deep one. If one change the address via the src
object, e.g. by doing src.at("address").set("city", "Manhattan")
, the change will be reflected in dest
as well. Also, both the phone and address values will now have the two parents src
and dest
. That is src.at("phone").up()
will be equals to the array [src, dest]
.
You can exercise control over the process via options. The with
method takes a sequence of options that govern how the copying is done. Different options are pertinent to objects and to arrays. Moreover, you can apply different options at different paths within a JSON structure. Maybe too much flexibility, but it's there if you need it. Here are the options:
- merge (for objects) - The properties of the source are recursively merged, instead of just copying the top-level properties. As a consequence, deeply nested properties in the destination object that do not appear in the source will be preserved.
- dup (for objects and arrays) - The properties of the source are cloned. In particular this means, that the values won't end up with the destination object as a parent.
-
sort (for arrays) - Perform a merge sort on arrays. Note that this assumes that arrays are already being maintained in order! If the arrays contain objects, you can use the
compareBy
option to indicate which property the objects should be compared by. -
compareBy (for arrays) - The name of the object property to compare array by during sort merge. The value of that property must be a
Comparable
(i.e. a number of a string).
Options driving the with
behavior can be specified at the top-level or at some nesting level. If you say:
dest.with(src, "dup")
That means the top-level object will be duplicated, and duplication/cloning is recursive anyway so you get a complete copy.
If instead you specify:
dest.with(src, "merge", object("for", ["address", "employer"], "dup", true))
It means that for the nested properties address
and employer
, the values will be duplicated. Note that the top-level "merge" option is specified as well, for otherwise, there won't be a recursive processing of the nested structures.
It must be noted that the above behaviors are provided by the default implementation of Json.Factory
and they are not mandated by the interface. They are also sort of experimental, which doesn't mean they are not supported or that they will be dropped - it just means, one must be careful when using them.