svenvc / neojson Goto Github PK
View Code? Open in Web Editor NEWNeoJSON is an elegant and efficient standalone Smalltalk framework to read and write JSON converting to or from Smalltalk objects.
License: MIT License
NeoJSON is an elegant and efficient standalone Smalltalk framework to read and write JSON converting to or from Smalltalk objects.
License: MIT License
Bug description
When sending #at:at: to a NeoJSONObject instance where key1 or key2 is missing, it does not signal an error but instead adds key 'errorKeyNotFound' with the missing key as value.
To reproduce
Open a playground and inspect the following:
NeoJSONObject new at: #key1 at: #key2
Expected behavior
Since sending a missing key with #at: returns nil, #at:at: should work the same.
Use something like OSPlatform current lineEnding
instead of the current character, which I believe is the default for old versions of Mac OSes. This can probably be set at class initialization time to not need to calculate many times at runtime
Our application deals with money, and therefore we avoid problems with Float, and use ScaledDecimal instead. But NeoJSONReader gives you a Float for instance:
| n1 n2 |
n1 := 1.14s2.
n2 := (NeoJSONReader on: (NeoJSONWriter toString: n1) readStream) next.
n1 - n2
My result is -2.22044604925031e-16
Yes, I could fix this in many of our classes with neoJsonMapping: methods. But wouldn't it be OK to just change #parseNumberFraction, which is the source of the Floats? Simple fix to change '1.0' to '1 asScaledDecimal', and '10.0' to '10' here:
parseNumberFraction
| number power |
number := 0.
power := 1 asScaledDecimal.
[ readStream atEnd not and: [ readStream peek isDigit ] ]
whileTrue: [
number := 10 * number + readStream next digitValue.
power := power * 10 ].
^ number / power
Consider integrating extension methods defined in BotwhythoGtExtensions package.
They enable parsing only a JSONPath while 'throwing out' unwanted data, all without having to create 'dummy' wrapper classes (potentially multiple layers of these) with mapping definitions when one only wants a leaf value.This is rather onerous if working with many ever changing third party data sources where one can't control the shape of the response.
The package adds the following extension methods:
NeoJSONReader>>#onlyParseProperty:
: Only return the value of a single top level property of a JSON object.NeoJSONReader>>#onlyParseProperty:as:
Same as previous, but specifying a schema for the value.NeoJSONReader>>#onlyJSONPath:
: Return the whole path of objects, basically nested map classes with only one key/value pair until the 'leaf' object is reached.NeoJSONReader>>#onlyJSONPath:as:
: Same as previous, but specifying a schema for the value.NeoJSONReader>>#onlyJSONPathLeafValue:
: Return only the leaf object of interest without the intermediary path.NeoJSONReader>>#onlyJSONPathLeafValue:as:
: Same as previous, but specifying a schema for the value.NeoJSONReader>>#normalizeIntoCollection:
: Helper method to normalize parametersHi, I'm writing a library for work with JSON-LD and I currently use generic mapping to Arrays and Dictionaries. However, due to how JSON-LD is defined, I do not know in any moment what the type of the object at hand is, and therefore I'm doing a lot of branching based on the type, which leads to long method bodies and just isn't very nice overall.
My question is, is it possible to tell NeoJSON to map the objects to multiple classes that I would create, so that I could use polymorphism instead? Or do you have recomendations on what I should do instead?
Code seems to be for Pharo and is not useable in other smalltalk systems without adaptions, e.g. String>>streamContents: is not available in VisualWorks.
This should be mentioned in the documentation.
Try inspecting the following
| o|
o := NeoJSONObject new.
o at: #x ifPresent: [] ifAbsentPut: [ 6 ].
o
It works in Pharo 9.
I am trying to use NeoJSON to deserialize some JSON structures. Everything goes well when i sue the default (dictionary) deserializer. I can even deserialize a structure into an instance for a single level. For instance say I have the class
Object subclass: #Car
instanceVariableNames: 'make model tires'
classVariableNames: ''
category: 'My-Models'
and the json
{
"make": "Ford",
"model": "Fiesta",
"tires": 4
}
then
(NeoJSONReader on: (json readStream))
mapInstVarsFor: Car;
nextAs: Car.
works, although it is a little verbose. But now assume I have a a class
Object subclass: #Driver
instanceVariableNames: 'name age car'
classVariableNames: ''
category: 'My-Models'
and the json
{
"name": "John Doe",
"age". 33,
"car": {
"make": "Ford",
"model": "Fiesta",
"tires": 4
}
}
Then in no way I am able to parse it as a Driver
instance with a property car
which is a Car
.
I have tried to use custom readers, but I found no way to say to map properties to instVars and then do the same in an inner level.
Is this possible with NeoJSON?
String containing characters \udbff\ue000 leads to invalid unicode codepoint U+110000, which is outside the max allowed codepoint U+10FFFF. Method parseCharacterHex in NeoJSONReader should throw an error in such case.
Possible code:
codePoint > 16r10FFFF
ifTrue: [self error: 'trailing surrogate ', trailSurrogate asBigEndianByteArray asHexString
, ' leads to invalid unicode codepoint ', codePoint asBigEndianByteArray asHexString]
This should probably be a continuation of the discussion in #11 , but GitHub doesn't seem to allow me to reopen it, so I am creating this one.
We have bumped into something similar to what @dallinjdahl is describing. We are sending some complex objects from OCaml over the wire to Smalltalk. Because ML is Hindley–Milner-typed, and these types are first-class data in OCaml, it's easy to automatically recreate the schema on the Smalltalk side. Obviously, we know the types for every node in that schema, so there will be leaves known to be Strings and leaves known to be Integers. The problem is that #nextAs:
does not allow its argument to be basic (i.e. you cannot do something like reader nextAs: String
). For now I am getting around this by modifying the implementation of #nextAs:
to check whether schema
is "primitive" and if so, use #next
instead. Here: master...shingarov:NeoJSON:ott
For me it works reasonably well, but I am not exactly happy to have my projects rely on a NeoJSON fork instead of contributing upstream. OTOH I am not convinced this is "the correct thing to do" so I am not creating a PR from the ott
branch, but I feel that at least an Issue discussion might be useful.
Because I don't want to load a development version, it would be nice to have a stable version of NeoJSON or at least a tag.
Considering JSON is a mix of lists and mappings and you can add keys/values to Dictionaries, you should also be able to add elements to a list in an object that represents JSON. This simplifies some use-cases like data wrangling and interactive manipulation of JSON API responses, for example.
If you are open to contributions, can definitely open a PR, let me know.
I use NeoJSONObject a lot as the overriding of doesNotUnderstand:
is GREAT for exploring deeply nested objects without getting very verbose in Pharo with many parenthesis and at:
sends.
Do something like below instead of current code.
^ (NeoJSONReader on: string readStream)
mapClass: NeoJSONObject;
listClass: OrderedCollection;
propertyNamesAsSymbols: true;
next
While this change is being considered, an even more flexible suggestion would be to subclass OrderedCollection (similarly to how NeoJSONObject subclasses Dictionary) and add a doesNotUnderstand:
that does something similar to what it does in NeoJSONObject. For example:
atN
unary method to get value at index N, for example at42
would return value at index 42. This enables introspecting into deeply nested objects more succinctly (i.e. myNeoJSONObject firstKey secondKey at42 thirdKey at7 fourthKey fifthKey
atN:
would set a value at index N. This is more for consistency as you can already use at:put:
but it could also make code slightly shorter.It is somewhat annoying to have all the keys in a NeoJSONObject
unsorted, given it is a subclass of Dictionary.
Wouldn't it be better to make NeoJSONObject
a subclass of OrderedDictionary
. This would make them easier to inspect and manipulate, and in the case that they were created by a NeoJSONReader
using as a map class, then it would honor the order in which the keys were defined in the original JSON string.
Pharo Version 7 both x86 and x64 on Windows.
run the code
Metacello new
repository: 'github://svenvc/NeoJSON/repository';
baseline: 'NeoJSON';
load.
To be clear, I can't get my end users to get github accounts or ssh keys just to load software. I'm also not going to put my ssh keys or github credentials into an image intended for distribution to the public.
I don't know why this is the only github repository that gives this issue.
Hi!
I just ported the current version to Gemstone 3.1.0.5 but I have trouble with a collection including obejcts within the same class hierarchy.
How would the neoJSONMapping: look like for a collection containing testObject2s and estObject3s ?
I trid to work with encoder and decoder custom mappings. But I can't get it working.
Could somebody please add an according test?
Thanks
Sebastian
I'm trying to provide a validated object from json, wherein I can guarantee that the types of the member variables are as expected. My thought was to do this with value schemas, but it appears that there are no mappings defined for reading basic classes? Specifically I'm trying to ensure that the member variables of an object are deserialized as an integer and bytestring respectively. Should I be extending those classes to implement #neoJsonMapping?
Hi,
NeoJSONWriter
do not preserve the order of fields which is defined in #neoJsonMapping:
declarations.
example :
neoJsonMapping: mapper
mapper for: self do: [ :mapping |
(mapping mapInstVar: #id) valueSchema: UUID.
(mapping mapInstVar: #text).
]
will produce:
{
"text" : "Do something",
"id" : "ee0a2a9c-ff32-0d00-ab55-ba1605c02387"
}
Maybe, using an OrderedDictionary
for properties in NeoJSONObjectMapping
could do the trick.
Cheers
method escapeUnicode: is missing in class NeoJSONWriter
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.