Skip to content

Commit b03c872

Browse files
committed
Deserialization to objects. Performance improvements
1 parent 12ae621 commit b03c872

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1438
-277
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## v0.5
4+
- Deserialization to objects
5+
- Performance improvements
6+
37
## v0.4
48
- JSON Proxy items added to imitate parsed JSON-nodes
59
- Added setters

README.md

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -71,29 +71,47 @@ println("To Double: " + res.find("object.message.attachments[0].wall.id").asDoub
7171
```
7272

7373
## Performance test
74-
Test code is in [iris/json/flow/test/performance_test.kt](https://github.com/iris2iris/iris-json-parser-kotlin/blob/master/src/iris/json/flow/test/performance_test.kt) file.
74+
75+
#### Array of 50 elements
76+
Test code is in [iris/json/flow/test/performance_array.kt](https://github.com/iris2iris/iris-json-parser-kotlin/blob/master/src/iris/json/flow/test/performance_array.kt) file.
7577

7678
Test JSON file is in [test_array.json](https://github.com/iris2iris/iris-json-parser-kotlin/blob/master/test_array.json) file.
7779

78-
Testing access to first element of array and access to last element of array.
80+
Testing access to first element of array and access to last element of array. 100k iterations
7981
```
8082
AVG[0]:
81-
org.json: 22611
82-
org.json.simple: 27232
83-
Iris Plain: 7110
84-
Iris Flow: 93
85-
Iris Proxy: 25
83+
org.json: 22363
84+
org.json.simple: 27080
85+
Iris Plain: 5394 // previous 7110
86+
Iris Flow: 564 // previous 93
87+
Iris Proxy: 27
8688
POJO: 11
8789
8890
AVG[49]:
89-
org.json: 22631
90-
org.json.simple: 27161
91-
Iris Plain: 7067
92-
Iris Flow: 7498
93-
Iris Proxy: 23
91+
org.json: 22416
92+
org.json.simple: 26869
93+
Iris Plain: 5411 // previous 7067
94+
Iris Flow: 5870 // previous 7498
95+
Iris Proxy: 26
9496
POJO: 10
9597
```
9698

99+
#### Complex json-tree structure
100+
101+
Test code is in [iris/json/flow/test/performance_object_tree.kt](https://github.com/iris2iris/iris-json-parser-kotlin/blob/master/src/iris/json/flow/test/performance_object_tree.kt) file.
102+
103+
Test JSON file is in [test.json](https://github.com/iris2iris/iris-json-parser-kotlin/blob/master/test.json) file.
104+
105+
Testing access to `object.message.attachments[0].wall.id` and converting it to Long. 100k iterations
106+
```
107+
org.json: 9149
108+
org.json.simple: 11186
109+
Iris Plain: 2652
110+
Iris Flow: 617
111+
Iris Proxy: 53
112+
POJO: 21
113+
```
114+
97115
Check out [CHANGELOG.md](https://github.com/iris2iris/iris-json-parser-kotlin/blob/master/CHANGELOG.md)
98116

99117
⭐ If this tool was useful for you, don't forget to give star.

src/iris/json/JsonItem.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package iris.json
22

3+
import iris.json.serialization.NodeInfo
4+
import kotlin.reflect.KClass
5+
36
/**
47
* @created 26.09.2020
58
* @author [Ivan Ivanov](https://vk.com/irisism)
@@ -13,7 +16,6 @@ interface JsonItem {
1316

1417
fun obj(): Any?
1518
fun <A: Appendable>joinTo(buffer: A): A
16-
override fun toString(): String
1719

1820
fun iterable() : Iterable<JsonItem>
1921

@@ -43,6 +45,10 @@ interface JsonItem {
4345

4446
fun asMap(): Map<String, Any?>
4547

48+
fun <T: Any>asObject(d: KClass<T>): T
49+
50+
fun <T: Any>asObject(info: NodeInfo): T
51+
4652
fun asStringOrNull(): String?
4753

4854
fun asString(): String
@@ -62,4 +68,6 @@ interface JsonItem {
6268
fun isObject(): Boolean
6369

6470
fun find(tree: String): JsonItem
71+
72+
6573
}

src/iris/json/JsonObject.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ package iris.json
44
* @created 26.09.2020
55
* @author [Ivan Ivanov](https://vk.com/irisism)
66
*/
7-
interface JsonObject: JsonItem, Iterable<JsonObject.Entry> {
8-
class Entry(val key: CharSequence, val value: JsonItem)
7+
8+
typealias JsonEntry = Pair<CharSequence, JsonItem>
9+
10+
interface JsonObject: JsonItem, Iterable<JsonEntry> {
11+
//class Entry(val key: CharSequence, val value: JsonItem)
912
}

src/iris/json/flow/FlowArray.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package iris.json.flow
33
import iris.json.JsonArray
44
import iris.json.JsonItem
55
import iris.json.proxy.JsonProxyUtil
6+
import iris.json.serialization.ListInfo
7+
import iris.json.serialization.NodeInfo
68

79
/**
810
* @created 20.09.2020
@@ -117,7 +119,7 @@ class FlowArray(tokener: Tokener) : FlowItem(tokener), JsonArray {
117119
override fun obj(): Any? {
118120
return obj ?: run {
119121
parse()
120-
obj = items.mapTo(mutableListOf()) { it.obj() }
122+
obj = items.mapTo(ArrayList(items.size)) { it.obj() }
121123
obj
122124
}
123125
}
@@ -149,4 +151,9 @@ class FlowArray(tokener: Tokener) : FlowItem(tokener), JsonArray {
149151
return get(pointer++)
150152
}
151153
}
154+
155+
override fun <T : Any> asObject(info: NodeInfo): T {
156+
parse()
157+
return (info as ListInfo).getObject(this.items) as T
158+
}
152159
}

src/iris/json/flow/FlowObject.kt

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,43 @@
11
package iris.json.flow
22

3+
import iris.json.JsonEntry
34
import iris.json.JsonItem
45
import iris.json.JsonObject
5-
import iris.json.JsonObject.Entry
66
import iris.json.plain.IrisJsonNull
77
import iris.json.proxy.JsonProxyUtil
8+
import iris.json.serialization.ClassInfo
9+
import iris.json.serialization.NodeInfo
10+
import java.util.*
811

912
/**
1013
* @created 20.09.2020
1114
* @author [Ivan Ivanov](https://vk.com/irisism)
1215
*/
1316
class FlowObject(tokener: Tokener) : FlowItem(tokener), JsonObject {
1417

15-
/*private class Entry(val key: CharSequence, val value: JsonItem) {
16-
override fun toString(): String {
17-
return "\"$key\": $value"
18-
}
19-
}*/
20-
2118
override fun get(ind: Int): JsonItem {
2219
return get(ind.toString())
2320
}
2421

25-
private val entries = mutableListOf<Entry>()
22+
private val entries = LinkedList<JsonEntry>()
2623

2724
private var isDone = false
2825
private var needToParse: FlowItem? = null
2926

3027
override fun get(key: String): JsonItem {
3128
for (e in entries) {
32-
if (e.key == key)
33-
return e.value
29+
if (e.first == key)
30+
return e.second
3431
}
3532
if (isDone) return IrisJsonNull.Null
3633
testNeedToParse()
3734
do {
3835
val next = parseNext() ?: break
3936
entries += next
40-
val nextVal = next.value as FlowItem
41-
if (next.key == key) {
37+
val nextVal = next.second as FlowItem
38+
if (next.first == key) {
4239
this.needToParse = nextVal
43-
return next.value
40+
return next.second
4441
}
4542
nextVal.parse()
4643
} while (true)
@@ -49,7 +46,7 @@ class FlowObject(tokener: Tokener) : FlowItem(tokener), JsonObject {
4946
return IrisJsonNull.Null
5047
}
5148

52-
private fun parseNext(): Entry? {
49+
private fun parseNext(): JsonEntry? {
5350
var char = tokener.nextChar()
5451
if (char == '}') {
5552
isDone = true
@@ -61,12 +58,12 @@ class FlowObject(tokener: Tokener) : FlowItem(tokener), JsonObject {
6158
if (!(char == '"' || char == '\''))
6259
throw tokener.exception("\" (quote) or \"'\" was expected")
6360

64-
val key = tokener.readString(char)
61+
val key = tokener.readFieldName(char)
6562
char = tokener.nextChar()
6663
if (char != ':')
6764
throw tokener.exception("\":\" was expected")
6865
val value = JsonFlowParser.readItem(tokener)
69-
return Entry(key, value)
66+
return JsonEntry(key, value)
7067
}
7168

7269
private var obj: MutableMap<String, Any?>? = null
@@ -75,21 +72,21 @@ class FlowObject(tokener: Tokener) : FlowItem(tokener), JsonObject {
7572
if (obj != null)
7673
return obj
7774
parse()
78-
val res = mutableMapOf<String, Any?>()
75+
val res = HashMap<String, Any?>(entries.size)
7976
for (it in entries)
80-
res[it.key.toString()] = it.value.obj()
77+
res[it.first.toString()] = it.second.obj()
8178
obj = res
8279
return res
8380
}
8481

8582
override fun set(key: String, value: Any?): JsonItem {
8683
val el = entries
87-
val index = el.indexOfFirst { it.key == key }
84+
val index = el.indexOfFirst { it.first == key }
8885
val wrapValue = JsonProxyUtil.wrap(value)
8986
if (index == -1)
90-
el += Entry(key, wrapValue)
87+
el += JsonEntry(key, wrapValue)
9188
else
92-
el[index] = Entry(key, wrapValue)
89+
el[index] = JsonEntry(key, wrapValue)
9390
val obj = obj
9491
if (obj != null) {
9592
obj[key] = value
@@ -107,9 +104,8 @@ class FlowObject(tokener: Tokener) : FlowItem(tokener), JsonObject {
107104
do {
108105
val next = parseNext() ?: break
109106
entries += next
110-
(next.value as FlowItem).parse()
107+
(next.second as FlowItem).parse()
111108
} while (true)
112-
113109
isDone = true
114110
}
115111

@@ -131,34 +127,38 @@ class FlowObject(tokener: Tokener) : FlowItem(tokener), JsonObject {
131127
else
132128
firstDone = true
133129
buffer.append("\"")
134-
buffer.append(entry.key)
130+
buffer.append(entry.first)
135131
buffer.append("\": ")
136-
entry.value.joinTo(buffer)
132+
entry.second.joinTo(buffer)
137133

138134
}
139135
buffer.append('}')
140136
return buffer
141137
}
142138

139+
override fun <T : Any> asObject(info: NodeInfo): T {
140+
parse()
141+
return (info as ClassInfo).getObject(entries)
142+
}
143+
143144
override fun isObject() = true
144145

145-
override fun iterator(): Iterator<Entry> {
146+
override fun iterator(): Iterator<JsonEntry> {
146147
// TODO: Надо бы тут парсить по мере итератора, а не всё сразу
147148
parse()
148149
return Iter()
149150
}
150151

151-
inner class Iter : Iterator<Entry> {
152+
inner class Iter : Iterator<JsonEntry> {
152153

153154
private val iterator = entries.iterator()
154155

155156
override fun hasNext(): Boolean {
156157
return iterator.hasNext()
157158
}
158159

159-
override fun next(): Entry {
160-
val e = iterator.next()
161-
return Entry(e.key, e.value)
160+
override fun next(): JsonEntry {
161+
return iterator.next()
162162
}
163163
}
164164
}

src/iris/json/flow/FlowString.kt

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package iris.json.flow
33
import iris.json.JsonString
44
import iris.json.plain.IrisJsonItem
55
import iris.json.plain.IrisJsonNull
6+
import iris.json.serialization.NodeInfo
67
import iris.sequence.IrisSequence
78

89
/**
@@ -11,13 +12,10 @@ import iris.sequence.IrisSequence
1112
*/
1213
class FlowString(tokener: Tokener, val quote: Char) : FlowItem(tokener), JsonString {
1314

14-
private val data: CharSequence by lazy(LazyThreadSafetyMode.NONE) { this.tokener.readString(quote) }
15-
16-
override fun toString(): String {
17-
return '"' + data.toString() + '"'
18-
}
15+
private var data: CharSequence? = null
1916

2017
override fun <A : Appendable> joinTo(buffer: A): A {
18+
parse()
2119
buffer.append('"')
2220
(data as? IrisSequence)?.joinTo(buffer) ?: buffer.append(data)
2321
buffer.append('"')
@@ -33,13 +31,16 @@ class FlowString(tokener: Tokener, val quote: Char) : FlowItem(tokener), JsonStr
3331
}
3432

3533
override fun parse() {
36-
data
34+
if (data == null)
35+
data = tokener.readString(quote)
3736
}
3837

39-
private val ready by lazy(LazyThreadSafetyMode.NONE) { init() }
38+
private var ready: String? = null// by lazy(LazyThreadSafetyMode.NONE) { init() }
4039

4140
private fun init(): String {
41+
parse()
4242
val res = StringBuilder()
43+
val data = data!!
4344
val len = data.length
4445
if (len == 0)
4546
return ""
@@ -88,7 +89,16 @@ class FlowString(tokener: Tokener, val quote: Char) : FlowItem(tokener), JsonStr
8889
}
8990
}
9091

91-
override fun obj() = ready
92+
override fun obj(): String {
93+
if (ready != null)
94+
return ready!!
95+
ready = init()
96+
return ready!!
97+
}
98+
99+
override fun <T : Any> asObject(info: NodeInfo): T {
100+
return obj() as T
101+
}
92102

93103
override fun isPrimitive() = true
94104
}

0 commit comments

Comments
 (0)