@@ -264,3 +264,78 @@ julia> pyonprint(stdout, [1, 2, nothing])
264
264
julia> sprint (pyonprint, missing )
265
265
" None"
266
266
```
267
+
268
+ #### Serialization
269
+
270
+ For cases where the JSON cosmetics are unimportant, but how objects are converted into their
271
+ JSON equivalents (arrays, objects, numbers, etc.) need to be changed, the appropriate
272
+ abstraction is ` Serialization ` . A ` Serialization ` instance is used as the second argument in
273
+ ` show_json ` . Thus, specializing ` show_json ` for custom ` Serialization ` instances enables
274
+ either creating more restrictive or different ways to convert objects into JSON.
275
+
276
+ The default serialization is called ` JSON.Serializations.StandardSerialization ` , which is a
277
+ subtype of ` CommonSerialization ` . Methods of ` show_json ` are not added to
278
+ ` StandardSerialization ` , but rather to ` CommonSerialization ` , by both ` JSON ` and by
279
+ other packages for their own types. The ` lower ` functionality is also specific to
280
+ ` CommonSerialization ` . Therefore, to create a serialization instance that inherits from and
281
+ may extend or override parts of the standard serialization, it suffices to define a new
282
+ serialization subtyping ` CommonSerialization ` . In the example below, the new serialization
283
+ is the same as ` StandardSerialization ` except that numbers are serialized with an additional
284
+ type tag.
285
+
286
+ ``` julia
287
+ import JSON. Serializations: CommonSerialization, StandardSerialization
288
+ import JSON. Writer: StructuralContext, show_json
289
+ struct TaggedNumberSerialization <: CommonSerialization end
290
+
291
+ tag (f:: Real ) = Dict (:type => string (typeof (f)), :value => f)
292
+ show_json (io:: StructuralContext ,
293
+ :: TaggedNumberSerialization ,
294
+ f:: Union{Integer, AbstractFloat} ) =
295
+ show_json (io, StandardSerialization (), tag (f))
296
+ ```
297
+
298
+ Note that the recursive call constructs a ` StandardSerialization() ` , as otherwise this would
299
+ result in a stack overflow, and serializes a ` Dict ` using that. In this toy example, this is
300
+ fine (with only the overhead of constructing a ` Dict ` ), but this is not always possible.
301
+ (For instance, if the constructed ` Dict ` could have other numbers within its values that
302
+ need to be tagged.)
303
+
304
+ To deal with these more complex cases, or simply to eliminate the overhead of constructing
305
+ the intermediate ` Dict ` , the ` show_json ` method can be implemented more carefully by
306
+ explicitly calling the context’s ` begin_object ` , ` show_pair ` , and ` end_object ` methods, as
307
+ documented above, and use the ` StandardSerialization() ` only for the ` show_pair ` call for
308
+ ` f ` .
309
+
310
+ ``` julia
311
+ # More careful implementation
312
+ # No difference in this case, but could be needed if recursive data structures are to be
313
+ # serialized in more complex cases.
314
+ import JSON. Writer: begin_object, show_pair, end_object
315
+ function show_json (io:: StructuralContext ,
316
+ s:: TaggedNumberSerialization ,
317
+ f:: Union{Integer, AbstractFloat} )
318
+ begin_object (io)
319
+ show_pair (io, s, :tag => string (typeof (f)))
320
+ show_pair (io, StandardSerialization (), :value => f)
321
+ end_object (io)
322
+ end
323
+ ```
324
+
325
+ To use the custom serialization, ` sprint ` can be used (and this can be encapsulated by a
326
+ convenient user-defined inteface):
327
+
328
+ ``` julia
329
+ julia> JSON. parse (sprint (show_json, TaggedNumberSerialization (), Any[1 , 2.0 , " hi" ]))
330
+ 3 - element Array{Any,1 }:
331
+ Dict {String,Any} (" value" => 1 ," type" => " Int64" )
332
+ Dict {String,Any} (" value" => 2.0 ," type" => " Float64" )
333
+ " hi"
334
+ ```
335
+
336
+ If it is not desired to inherit all the functionality of ` StandardSerialization ` , users may
337
+ also choose to start from scratch by directly subtyping ` JSON.Serializations.Serialization ` .
338
+ This is useful if the user wishes to enforce a strict JSON which throws errors when
339
+ attempting to serialize objects that aren’t explicitly supported. Note that this means you
340
+ will need to define a method to support serializing any kind of object, including the
341
+ standard JSON objects like booleans, integers, strings, etc.!
0 commit comments