|
Class: JSONReader
Object
|
+--Stream
|
+--PeekableStream
|
+--JSONReader
- Package:
- stx:goodies/communication
- Category:
- Net-Communication-JSON
- Version:
- rev:
1.81
date: 2024/04/22 17:04:03
- user: stefan
- file: JSONReader.st directory: goodies/communication
- module: stx stc-classLibrary: communication
I read data structures (currently build of OrderedCollection and Dictionary)
from and to JSON (Java Script Object Notation).
Writing is done with the #toJSON: class-method (note: it will behave badly with circular data structures).
Reading via the #fromJSON: class-method.
Notice:
By default (and standard),
Date, Time and Timestamps are written as iso8601 strings,
and read initially as strings (thus, they must be converted explicitely back if required).
The non-standard (but supported by some browsers) format is 'new Date(...)' which is generated
optionally, if the useISODateFormat flag is turned off in the JSONPrinter.
However, we cannot read back this format.
As per ECMA,
JSON.stringify({'now': new Date()})
should generate
{''now'':''2013-10-21T13:28:06.419Z''}
which is exactly what JSONPrinter now generates by default
JSONPrinter encode:(Structure with: #now -> (Timestamp now)).
Another Note:
Can now also encode arbitrary Smalltalk objects; however, the reader will always decode them
as dictionaries:
JSONPrinter encode:(Point x:10 y:20).
JSONReader decode:(JSONPrinter encode:(Point x:10 y:20)).
Final Notice:
take a look at the other (alternative) JSON framework (Json),
which can also be used to handle JSON data, and offers a more flexible
object mapping mechanism to decode into real objects.
Extensability:
allows for special encodings to be hooked in by passing a
dictionary mapping keywords to handler blocks.
The block is called if a hash followed by the keyword is scanned.
Can be used to add special encodings for private communications
(be aware that extensions are NOT conforming any standard, and are to
be used ONLY for private protocols)
Author:
Public Domain Code from Robin Redeker published in lists.gnu.org
adapted to ST/X by Claus Gittinger
copyrightCOPYRIGHT (c) 2007 by eXept Software AG
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
API - decoding
-
decode: stringOrStream
-
decode the JSON string (as received from JavaScript) to an object
-
decode: stringOrStream extensions: extensionsOrNil
-
decode the JSON string (as received from JavaScript) to an object
-
decode: stringOrStream typeInfoFormat: formatSymbolOrNilOrDecoder
-
decode the JSON string (as received from JavaScript) to an object.
The formatSymbolOrNilOrDecoder argument can be either a symbol for one of the standard decoders
(nil, #stx or #stx2), or an instantiated decoder instance provided by the caller
-
decode: stringOrStream typeInfoFormat: formatSymbolOrNilOrDecoder verifyEOF: verifyEOF
-
decode the JSON string (as received from JavaScript) to an object.
Rhe formatSymbolOrNilOrDecoder argument can be either a symbol for one of the standard decoders
(nil, #stx or #stx2), or an instantiated decoder instance provided by the caller
-
decode: stringOrStream typeInfoFormat: formatSymbolOrNilOrDecoder verifyEOF: verifyEOF extensions: extensionsOrNil
-
decode the JSON string (as received from JavaScript) to an object.
The formatSymbolOrNilOrDecoder argument can be either a symbol for one of the standard decoders
(nil, #stx or #stx2), or an instantiated decoder instance provided by the caller
-
decode: stringOrStream typeInfoFormat: formatSymbolOrNilOrDecoder verifyEOF: verifyEOF extensions: extensionsOrNil classNamespace: classNameSpaceToUse
-
decode the JSON string (as received from JavaScript) to an object.
The formatSymbolOrNilOrDecoder argument can be either a symbol for one of the standard decoders
(nil, #stx or #stx2), or an instantiated decoder instance provided by the caller.
If the type is non-nil, an optional namespace may be passed to the
decoder, telling it where to look for classes being loaded
(i.e. the @type slots can then decode class names from private namespaces
-
defaultJSON5
-
-
defaultJSON5: aBoolean
-
-
fromJSON5: stringOrStream
-
decode the JSON5 string (as received from JavaScript) to an object.
Same as decode:
Added to make the decoder protocol-conform to other encoders.
-
fromJSON: stringOrStream
-
decode the JSON string (as received from JavaScript) to an object.
Same as decode:
Added to make the decoder protocol-conform to other encoders.
-
fromJSON: stringOrStream extensions: extensions
-
decode the JSON string (as received from JavaScript) to an object.
Same as decode:
Added to make the decoder protocol-conform to other encoders.
-
readFrom: stringOrStream
-
decode the JSON string (as received from JavaScript) to an object.
Same as decode:
Added to make the decoder protocol-conform to other encoders.
API - encoding
-
encode: anObject
-
return a JSON string which represents the object (can be sent to JavaScript).
Same as toJSON:
Added to make this more protocol-conform to other encoders.
Usage example(s):
|s1 s2|
s1 := self encode:#('hello' 123 true (1 'two' 3.0)).
s2 := self decode:s1
|s1 s2|
s1 := self encode:#[10 20 30].
s2 := self decode:s1
|s1 s2|
s1 := self encode:#('aaa' 'bbb' 'ccc').
s2 := self decode:s1
|
-
toJSON: anObject
-
return a JSON string which represents the object (can be sent to JavaScript).
Same as encode:
Added to make this more protocol-conform to other encoders.
Usage example(s):
|s1 s2|
s1 := self toJSON:#('hello' 123 true (1 'two' 3.0)).
s2 := self fromJSON:s1
|
Usage example(s):
|s1 s2|
s1 := self toJSON:(Dictionary withKeys:#('a' 'b' 'c') andValues:#(1 2 3)).
s2 := self fromJSON:s1
|
-
toJSON: anObject on: aStream
-
append a JSON string which represents the object (can be sent to JavaScript)
to aStream.
Same as encode:
Added to make this more protocol-conform to other encoders.
Usage example(s):
self toJSON:#('hello' 123 true (1 'two' 3.0)) on:Transcript.
|
-
toJSON: anObject typeInfoFormat: formatSymbolOrNil on: aStream
-
append a JSON string which represents the object (can be sent to JavaScript)
to aStream.
Same as encode:
Added to make this more protocol-conform to other encoders.
Usage example(s):
self toJSON:#('hello' 123 true (1 'two' 3.0)) on:Transcript.
|
instance creation
-
new
-
return an initialized instance
-
on: aStream
-
accessing
-
extensions: extensionsDictionary
-
Modified (format): / 20-12-2021 / 09:42:06 / cg
initialization
-
allowJSON5: aBoolean
-
enable/disable JSON5 features
-
classNamespace: aNamespace
-
-
initialize
-
JSONPrinter encode:((10@20) corner:(100@200))
-
makeSlotDecoderFor: typeInfoFormatOrDecoder
-
the argument can be either a symbol for one of the standard decoders
(nil, #stx or #stx2), or an instantiated decoder instance provided by the caller
-
typeInfoFormat: formatSymbolOrNil
-
specify the format of the type info to be store with the slots.
For now, the formats supported are:
nil (default): no type info (standard JSON)
#stx : encode as { '@type': , <classNameString> , 'value': <encoding> }
#stx2 : encode as { '@type': , <classNameString> , slots... }
more formats may be implemented in the future.
-
typeSlotName: aString
-
private
-
atEnd
-
(comment from inherited method)
return true if the end of the stream has been reached;
- we do not know here how to do it, it must be redefined in subclass
-
next
-
I'm returning the next non-whitespace character
-
nextExtension
-
#key ... to call extension 'key' passing the input stream which is positioned
at the character after key
-
nextJSONArray
-
I decode JSON arrays from self and will return an Array for them.
-
nextJSONDict
-
I decode JSON objects from self and will return a Dictionary containing all the key/value pairs.
-
nextJSONNumber
-
I'm extracting a number in JSON format from self and return Integer or Float depending on the input.
Accepts NaN, +Inf and -Inf.
If the allowJSON5 flag is true, also allow base2 and base16 numbers (0bXXXX and 0xXXXX)
-
nextJSONNumber: peekC
-
I'm extracting a number in JSON format from self and return Integer or Float depending on the input.
Accepts NaN, +Inf and -Inf.
If the allowJSON5 flag is true, also allow base2 and base16 numbers (0bXXXX and 0xXXXX)
-
nextJSONString
-
I'm extracting a JSON string from self and return it as String.
-
nextJSONString: quote
-
I'm extracting a JSON string from my stream and return it as String.
The quote character is assumed to be last read.
-
peek
-
I'm peeking for the next non-whitespace character
and will drop all whitespace in front of it and (for JSON5) all C-style comments.
Don't call me when reading the contents of a string
-
stream: aStream
-
reading
-
decode: stringOrStream
-
-
nextJSONObject
-
I decode a json self to a value, which will be one of:
nil, true, false, OrderedCollection, Dictionary, String or Number
(I will return Integer or Float depending on the input).
Somewhat picky on the input (expects 'null', 'true', 'false' to be written as that
|o1 s o2|
o1 := OrderedDictionary new.
o1['a'] := 1.
o1['b'] := true.
s := JSONPrinter toJSON:o1.
o2 := JSONReader fromJSON:s.
self assert:(o1 sameContentsAs: o2).
|
|o1 s o2|
o1 := OrderedDictionary new.
o1['aaa'] := 'AAA'.
o1['bbb'] := 123.
o1['ccc'] := 1.
s := JSONPrinter toJSON:o1.
o2 := JSONReader fromJSON:s.
self assert:(o1 = o2).
|
|o1 s o2|
o1 := #('hello' 123 nil true false (1 'two' 3.0) -4 -1.5).
s := JSONPrinter toJSON:o1.
o2 := JSONReader fromJSON:s.
self assert:(o1 = o2).
|
|o1 s o2|
o1 := InlineObject slotNames:#('foo' 'bar' 'baz') values:#(1 2 3).
s := JSONPrinter toJSON:o1.
o2 := JSONReader fromJSON:s.
|
|o1 s o2|
o1 := OrderedDictionary withKeys:#('foo' 'bar' 'baz') andValues:#(1 2 3).
s := JSONPrinter toJSON:o1.
o2 := JSONReader fromJSON:s.
self assert:(o1 = o2).
|
|o1 s o2|
o1 := Dictionary withKeysAndValues:#('one' 1 'two' 2 'three' 3.0 'four' 'vier').
s := JSONPrinter toJSON:o1.
o2 := JSONReader fromJSON:s.
self assert:(o1 sameContentsAs: o2).
|
|o1 s o2|
o1 := Dictionary withKeysAndValues:#('one two three' 123).
s := JSONPrinter toJSON:o1.
o2 := JSONReader fromJSON:s.
self assert:(o1 sameContentsAs: o2).
|
|o1 s o2|
o1 := { Date today . Time now . Timestamp now }.
s := JSONPrinter encode:o1.
o2 := JSONReader decode:s.
-- notice: data & times are decoded as strings
|
|o1 s o2|
o1 := { Point x:10 y:20 }.
s := JSONPrinter new useISODateFormat:false; encode:o1.
o2 := JSONReader decode:s.
self assert:(o1 sameContentsAs: o2).
|
|o1 s o2|
o1 := { Date today . Time now . Timestamp now }.
s := JSONPrinter new useISODateFormat:false; encode:o1.
o2 := JSONReader decode:s -- fails as non-JSON
|
notice: byteArray encoded as array - will decode as array
|o1 s o2|
o1 := #[1 2 3].
s := JSONPrinter toJSON:o1.
o2 := JSONReader fromJSON:s
|
using extensions
|ext o|
ext := Dictionary new.
ext at:#foo put:[:in | in next. Integer readFrom:in. ].
o := JSONReader fromJSON:'{ ',Character doubleQuote,'bla',Character doubleQuote,': #foo:1234 }' extensions:ext.
self assert:(o bla == 1234).
|
|