/
JsonModel.kt
120 lines (100 loc) · 3.43 KB
/
JsonModel.kt
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
package com.github.harshadnawathe.fusionkt.json
import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.JsonSerializer
import com.fasterxml.jackson.databind.SerializerProvider
import com.fasterxml.jackson.databind.annotation.JsonSerialize
import com.fasterxml.jackson.databind.node.ArrayNode
import com.fasterxml.jackson.databind.node.JsonNodeFactory
import com.fasterxml.jackson.databind.node.ObjectNode
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.jacksonTypeRef
import java.io.File
@JsonSerialize(using = JsonModelSerializer::class)
class JsonModel<T>(
private val type: TypeReference<T>,
private val json: JsonNode
) {
val isComplete: Boolean
get() = try {
value.let { true }
} catch (_: Throwable) {
false
}
val value: T by lazy {
mapper.convertValue(json, type)
}
infix fun with(override: Any): JsonModel<T> {
return when (override) {
is JsonModel<*> -> this with override.json
else -> JsonModel(
type = type,
json = mapper.updateValue(json, override)
)
}
}
companion object {
val mapper = jacksonObjectMapper()
inline fun <reified T> of(): JsonModel<T> {
return JsonModel(
type = jacksonTypeRef(),
json = mapper.createObjectNode()
)
}
inline fun <reified T> from(value: T): JsonModel<T> {
return JsonModel(
type = jacksonTypeRef(),
json = mapper.valueToTree(value)
)
}
inline fun <reified T> from(jsonText: String): JsonModel<T> {
return JsonModel(
type = jacksonTypeRef(),
json = mapper.readTree(jsonText)
)
}
inline fun <reified T> from(file: File): JsonModel<T> {
return JsonModel(
type = jacksonTypeRef(),
json = mapper.readTree(file)
)
}
inline fun <reified T> of(block: JsonNodeBuilder.() -> Unit): JsonModel<T> {
return JsonModel(
type = jacksonTypeRef(),
json = JsonNodeBuilder().apply(block).node
)
}
}
}
interface JsonModelCustomizer {
val array: JsonArrayBuilder
infix fun String.having(value: Any?)
fun obj(block: JsonNodeBuilder.() -> Unit): Any
}
class JsonNodeBuilder : JsonModelCustomizer {
override val array = JsonArrayBuilder()
val node: ObjectNode = JsonNodeFactory.instance.objectNode()
override infix fun String.having(value: Any?) {
node.putPOJO(this, value)
}
override fun obj(block: JsonNodeBuilder.() -> Unit): Any {
return JsonNodeBuilder().apply(block).node
}
}
class JsonArrayBuilder {
private val factory = JsonNodeFactory.instance
operator fun get(vararg elements: Any?): ArrayNode {
return factory.arrayNode().let { node ->
elements.fold(node) { acc, any ->
acc.addPOJO(any)
}
}
}
}
class JsonModelSerializer : JsonSerializer<JsonModel<*>>() {
override fun serialize(jsonModel: JsonModel<*>, gen: JsonGenerator, serializers: SerializerProvider) {
gen.writeObject(jsonModel.value)
}
}