That you very much for your input and a great library. I will use a variation of the second solution. On 20 August 2012 15:34, Sven Van Caekenberghe <sven@beta9.be> wrote:
Hi Milan,
On 20 Aug 2012, at 14:02, Milan Mimica <milan.mimica@gmail.com> wrote:
Hello
I have obtained a json from a HTTP response which looks like:
{"login":{"verified":true,"authCookie":"2eb62b41-5156-4056-9b5d-9252b52c93a2"}}
I want to map this into a Smalltalk class LoginResponse which has two
instance variables: verified and authCookie. So I need the mapper to ignore the root property name "login". I think that is a quite common use case. How can it be done?
-- Milan Mimica http://sparklet.sf.net
I understand your question, but currently there is no out of the box support for class/type mapping using maps like in your example (there are other variation too, like class/type properties, nested or not). The reason is that this involves schema checking which I didn't want to do due to the added complexity and lack of standardization (this is intentionally outside the JSON spec proper).
You have 2 options:
- either use generic parsing and do the conversions and schema checking after the parsing (which is what most JSON parser make you do anyway)
NeoJSONReader fromString: '{"login":{"verified":true,"authCookie":"2eb62b41-5156-4056-9b5d-9252b52c93a2"}}'.
- write a custom mapping that looks a bit like a hack
(NeoJSONReader on: '{"login":{"verified":true,"authCookie":"2eb62b41-5156-4056-9b5d-9252b52c93a2"}}' readStream) for: #LoginResponseWrapper customDo: [ :mapping | mapping reader: [ :jsonReader | | result | result := nil. jsonReader parseMapKeysDo: [ :key | key = #login ifTrue: [ result := jsonReader next ] ]. result ] ]; nextAs: #LoginResponseWrapper
the above example will go into the login element if it is present and return a dictionary.
To make it return your class, this should do the trick
(NeoJSONReader on: '{"login":{"verified":true,"authCookie":"2eb62b41-5156-4056-9b5d-9252b52c93a2"}}' readStream) mapInstVarsFor: LoginResponse; for: #LoginResponseWrapper customDo: [ :mapping | mapping reader: [ :jsonReader | | result | result := nil. jsonReader parseMapKeysDo: [ :key | key = #login ifTrue: [ result := jsonReader nextAs: LoginResponse ] ]. result ] ]; nextAs: #LoginResponseWrapper
I can image a more general purpose LoginResponseWrapper that maps multiple types at once.
HTH,
Sven
-- Sven Van Caekenberghe http://stfx.eu Smalltalk is the Red Pill
-- Milan Mimica http://sparklet.sf.net