1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# ............................................................................................... #
#
# Copyright (c) 2012-2017 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License v1.0
# which accompanies this distribution, and is available at
# http://www.eclipse.org/legal/epl-v10.html
#
# ............................................................................................... #
----
A set of useful APIs for dealing with JSON documents from Golo.
The implementation is backed by [json-simple](https://code.google.com/p/json-simple/). While
`json-simple` only supports encoding from lists and maps, this API brings support for sets, arrays,
Golo tuples, dynamic objects and structs.
----
module gololang.JSON
# ............................................................................................... #
----
Takes any know object, and gives a JSON string representation:
let data = map[
["name", "Somebody"],
["age", 69],
["friends", list[
"Mr Bean", "John B", "Larry"
]]
]
let asText = JSON.stringify(data)
`obj` may be a list, an array, a set, a map, a tuple, a dynamic object or a struct. If `obj` is from
another type then its string representation is given according to `obj: toString()` or `"null"` if
`obj` is `null`.
----
function stringify = |obj| {
let res = stringify_walk(obj)
if (res is null) {
return "null"
} else {
return res: toString()
}
}
local function isSeq = |obj| ->
(obj oftype java.util.List.class) or
(obj oftype java.util.Set.class) or
(obj oftype gololang.Tuple.class) or
(isArray(obj))
local function stringify_walk = |obj| {
if obj oftype java.util.Map.class {
let json = org.json.simple.JSONObject()
foreach key in obj: keySet() {
json: put(key, stringify_walk(obj: get(key)))
}
return json
} else if isSeq(obj) {
let json = org.json.simple.JSONArray()
foreach value in obj {
json: add(stringify_walk(value))
}
return json
} else if obj oftype gololang.DynamicObject.class {
let json = org.json.simple.JSONObject()
foreach prop in obj: properties() {
let value = prop: getValue()
if not(isClosure(value)) {
json: put(prop: getKey(), stringify_walk(value))
}
}
return json
} else if (obj oftype gololang.GoloStruct.class) {
let json = org.json.simple.JSONObject()
foreach member in obj: members() {
json: put(member, stringify_walk(obj: get(member)))
}
return json
}
return obj
}
----
Parses a JSON string and gives an object representation as a list or map collection:
let data = JSON.parse(text)
println(data: get("name"))
----
function parse = |str| -> org.json.simple.JSONValue.parseWithException(str)
# ............................................................................................... #
----
Provides a mixin for dynamic objects that includes a `toJSON()` method:
object: mixin(JSON.dynamicObjectMixin()): toJSON()
which is equivalent to:
JSON.stringify(object)
----
function dynamicObjectMixin = ->
DynamicObject(): define("toJSON", |this| -> stringify(this))
----
Returns a new dynamic object from a JSON string where each first-level entry is mapped into the
dynamic object:
let obj = JSON.toDynamicObject(JSON.stringify(map[
["a", "1"], ["b", "2"]
]))
println(obj: a())
println(obj: b())
----
function toDynamicObject = |str| {
let obj = DynamicObject()
let map = parse(str)
foreach key in map: keySet() {
obj: define(key, map: get(key))
}
return obj
}
# ............................................................................................... #
----
JSON augmentations for structs.
----
augment gololang.GoloStruct {
----
Conveniently adds a `toJSON()` method, which is equivalent to calling `JSON.stringify()`:
struct Person = { name, age, email }
# (...)
Person("Mr Bean", "mrbean@outlook.com", 64): toJSON()
----
function toJSON = |this| -> stringify(this)
----
Populates the elements of a struct based on the values found in a JSON string.
let str = JSON.stringify(map[
["name", "Foo"],
["email", "foo@gmail.com"],
["age", 99],
["gender", "N/A"]
])
let foo = Person(): updateFromJSON(str)
Note that missing entries from the JSON data yield `null` values in the struct.
----
function updateFromJSON = |this, str| {
let map = parse(str)
foreach member in this: members() {
this: set(member, map: get(member))
}
return this
}
}
# ............................................................................................... #