[Pharo-users] Understanding ZnJSONReader mapping?

Esteban A. Maringolo emaringolo at gmail.com
Thu Jun 7 16:44:59 EDT 2018

On 07/06/2018 17:21, Tim Mackinnon wrote:
> Hi - is there something I can read/study to get a bit more familiar with Json mapping? I have read the Pharo enterprise book (chapter 8).
> I’ve been using NeoJSONObject but then it occurred to me that maybe I could map better domain objects directly and simplify things. However it seems that the intent of mapping is just for simple things like an array of points - whereas if I have 15 different domain objects (albeit with a type key), then I’m wondering if I should just wrap json nodes on usage? 
> In fact I’m wondering what the point of mapping is if it’s so simple - or maybe I’m missing an important concept?
If your objects just hold data, then you can get very far with
NeoJSONObject, but if you want to do more, you can get pretty extensible
mappings with the use of the valueSchema: option in the mapper.

For instance, to write a TsOrder (a model of an purchase order) I
configured the mapper this way:

mapper for: TsOrder do: [ :mapping |
  mapping mapAccessors: #(id).
 (mapping mapAccessor: #date) valueSchema: Date.
 (mapping mapAccessor: #edd) valueSchema: #NamedModel.
 (mapping mapAccessor: #provider) valueSchema: #NamedModel.
 (mapping mapAccessor: #status) valueSchema: #NamedModel.
 (mapping mapAccessor: #customerCode).
 (mapping mapAccessor: #totalOriginalPrice to: 'total') valueSchema:

mapper for: Date customDo: [ :mapping |
    mapping encoder: [ :date | date ddmmyyyy  ] ].

mapper for: #monetary customDo: [ :mapping |
    mapping encoder: [ :price | price printShowingDecimalPlaces: 2 ] ].

mapper for: DateAndTime customDo: [ :mapping |
    mapping decoder: [ :string | DateAndTime fromString: string ].

mapper for: #NamedModel customDo: [ :mapping |
    mapping encoder: [ :persona | persona displayString ] ].

For decoding it might be trickier, because you might need more objects
other than just deserializing from JSON, e.g. to avoid instantiating
twice the same domain object, or if you need to lookup an entity in the
database by ID, and then you need access to the database, etc.

Throughout my journey of developing a few JSON-REST APIs I started using
the NeoJSON approach, then JsonObject and then WAJsonCanvas.

I found myself more confortable writing JSON with the latter (I like the
canvas approach of Seaside) and instantiating NeoJSONObject/JsonObject
and building my business objects from these cherry picking what I needed.

What NeoJSON offers as a "differentiator" is that it is stream based, so
there is no need to have intermediate "structures" (it is,
dictionaries), and the mappers are orthogonal to the objects (unless you
use the default class side #neoJsonMapping:)

WAJsonCanvas offers stream based writing, but there are no mappings, but
if you always serialize a proper hierarchy of renderJsonOn: implementors
could prove to be effective, in particular if you have to build your
objects manually from a JSON stream.


Esteban A. Maringolo

More information about the Pharo-users mailing list