Skip to content

Commit 7fab4ef

Browse files
committed
DeserializerFactory.getDeserializer now also looks for deserializers for superclasses of target Class.
1 parent 60120ea commit 7fab4ef

File tree

11 files changed

+212
-97
lines changed

11 files changed

+212
-97
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
package iris.json.serialization
22

33
import iris.json.JsonItem
4+
import kotlin.reflect.KClass
45

56
/**
67
* @created 08.10.2020
78
* @author [Ivan Ivanov](https://vk.com/irisism)
89
*/
910
interface Deserializer {
1011
fun <T>deserialize(item: JsonItem): T
12+
fun forSubclass(d: KClass<*>): Deserializer
1113
}
1214

src/iris/json/serialization/DeserializerClass.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@ package iris.json.serialization
33
import iris.json.JsonEntry
44

55
interface DeserializerClass : Deserializer {
6-
fun <T: Any>getObject(entries: Collection<JsonEntry>): T
6+
fun <T>getObject(entries: Collection<JsonEntry>): T
77
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package iris.json.serialization
2+
3+
import kotlin.reflect.KClass
4+
import kotlin.reflect.KFunction
5+
import kotlin.reflect.KParameter
6+
import kotlin.reflect.KProperty
7+
import kotlin.reflect.full.findAnnotation
8+
import kotlin.reflect.full.memberProperties
9+
10+
/**
11+
* @created 11.10.2020
12+
* @author [Ivan Ivanov](https://vk.com/irisism)
13+
*/
14+
object DeserializerClassBuilder {
15+
fun build(d: KClass<*>): DeserializerClassImpl {
16+
var hasPolymorphies = false
17+
val constructorInfo = getFieldsOrder(d.constructors)
18+
val (constr, constructorFields) = constructorInfo
19+
20+
val mProperties = d.memberProperties
21+
val fieldsList = mProperties.associateTo(HashMap(mProperties.size)) { property ->
22+
val objectItemName = property.name
23+
val jsonItemName = property.findAnnotation<JsonField>()?.name
24+
?.let { t -> if(t.isNotEmpty()) t else objectItemName }
25+
?: objectItemName
26+
val p = getPropertyInfo(property, constructorFields.find { it.name == objectItemName })
27+
if (!hasPolymorphies && p.polymorphInfo != null)
28+
hasPolymorphies = true
29+
jsonItemName to p
30+
}
31+
32+
return DeserializerClassImpl(constr, fieldsList, hasPolymorphies)
33+
}
34+
35+
private fun getPropertyInfo(it: KProperty<*>, constructorParameter: KParameter?): DeserializerClassImpl.PropertyInfo {
36+
val tType = DeserializerPrimitiveImpl.convertType(it.returnType, null)
37+
var type: DeserializerPrimitiveImpl? = null
38+
var inheritInfo: DeserializerClassImpl.PolymorphInfo? = null
39+
var innerClass: Deserializer? = null
40+
if (tType != null) { // simple type int/string/boolean
41+
type = tType
42+
} else { // there some complex class
43+
val data = it.findAnnotation<PolymorphData>()
44+
if (data != null) { // is polymorphic
45+
val cases = mutableMapOf<Any, Deserializer>()
46+
data.strings.associateTo(cases) { it.label to DeserializerFactory.getDeserializer(it.instance) }
47+
data.ints.associateTo(cases) { it.label to DeserializerFactory.getDeserializer(it.instance) }
48+
inheritInfo = DeserializerClassImpl.PolymorphInfo(data.sourceField, cases)
49+
} else {
50+
innerClass = DeserializerFactory.getDeserializer(it.returnType)
51+
}
52+
}
53+
54+
return DeserializerClassImpl.PropertyInfo(/*it.name, */it, constructorParameter, type, innerClass, inheritInfo)
55+
}
56+
57+
private fun getFieldsOrder(constructors: Collection<KFunction<*>>): Pair<KFunction<*>, List<KParameter>> {
58+
var best: KFunction<*>? = null
59+
for (c in constructors)
60+
if (best == null || c.parameters.size > best.parameters.size)
61+
best = c
62+
if (best == null)
63+
throw IllegalArgumentException("No any constructor")
64+
return best to best.parameters
65+
}
66+
}

src/iris/json/serialization/DeserializerClassImpl.kt

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,7 @@ import iris.json.JsonItem
55
import iris.json.JsonObject
66
import java.util.*
77
import kotlin.collections.HashMap
8-
import kotlin.reflect.KFunction
9-
import kotlin.reflect.KMutableProperty
10-
import kotlin.reflect.KParameter
11-
import kotlin.reflect.KProperty
8+
import kotlin.reflect.*
129

1310
/**
1411
* @created 08.10.2020
@@ -29,7 +26,11 @@ class DeserializerClassImpl(private val constructorFunction: KFunction<*>, priva
2926
return getObject((item as JsonObject).getEntries())
3027
}
3128

32-
override fun <T: Any>getObject(entries: Collection<JsonEntry>): T {
29+
override fun forSubclass(d: KClass<*>): Deserializer {
30+
return this
31+
}
32+
33+
override fun <T>getObject(entries: Collection<JsonEntry>): T {
3334
val info = this
3435
val fields = info.fields
3536
val hasPolymorphisms = info.hasPolymorphisms
@@ -61,9 +62,9 @@ class DeserializerClassImpl(private val constructorFunction: KFunction<*>, priva
6162
} else { // need delay initialization until we know source info
6263
val item = delayedInit!![polymorphInfo.sourceField]
6364
if (item == null)
64-
delayedInit[polymorphInfo.sourceField] = Delayed(Delayed.Data(/*field, */param, jsonItem))
65+
delayedInit[polymorphInfo.sourceField] = Delayed(Delayed.Data(param, jsonItem))
6566
else
66-
item.add(Delayed.Data(/*field, */param, jsonItem))
67+
item.add(Delayed.Data(param, jsonItem))
6768
}
6869
} else {
6970
val value = getValue(jsonItem, param)
@@ -73,15 +74,15 @@ class DeserializerClassImpl(private val constructorFunction: KFunction<*>, priva
7374
val item = delayed.firstItem
7475
val property = item.propertyInfo
7576
val inherit = property.polymorphInfo!!.inheritClasses[value]!!
76-
val newValue: Any = inherit.deserialize(item.json)//.asObject(inherit)
77+
val newValue: Any = inherit.deserialize(item.json)
7778
item.propertyInfo.constructorParameter?.let { constructorMap[it] = newValue }
7879
?: run { otherFields += property.property to newValue }
7980

8081
if (delayed.items != null) {
8182
for (item in delayed.items!!) {
8283
val property = item.propertyInfo
8384
val inherit = property.polymorphInfo!!.inheritClasses[value]!!
84-
val newValue: Any = inherit.deserialize(item.json)//.asObject(inherit)
85+
val newValue: Any = inherit.deserialize(item.json)
8586
item.propertyInfo.constructorParameter?.let { constructorMap[it] = newValue }
8687
?: run { otherFields += property.property to newValue }
8788
}
@@ -102,7 +103,7 @@ class DeserializerClassImpl(private val constructorFunction: KFunction<*>, priva
102103
}
103104

104105
private class Delayed(val firstItem: Data) {
105-
class Data(/*val field: String, */val propertyInfo: PropertyInfo, val json: JsonItem)
106+
class Data(val propertyInfo: PropertyInfo, val json: JsonItem)
106107

107108
var items: MutableList<Data>? = null
108109
fun add(item: Data) {

src/iris/json/serialization/DeserializerCollectionImpl.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package iris.json.serialization
22

33
import iris.json.JsonArray
44
import iris.json.JsonItem
5+
import kotlin.reflect.KClass
56

67
/**
78
* @created 08.10.2020
@@ -19,4 +20,8 @@ class DeserializerCollectionImpl(val typeDeserializer: Deserializer) : Deseriali
1920
override fun <T> deserialize(item: JsonItem): T {
2021
return getObject((item as JsonArray).getList()) as T
2122
}
23+
24+
override fun forSubclass(d: KClass<*>): Deserializer {
25+
return this
26+
}
2227
}
Lines changed: 16 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package iris.json.serialization
22

33
import iris.json.JsonItem
4-
import iris.json.serialization.DeserializerClassImpl.PolymorphInfo
5-
import iris.json.serialization.DeserializerClassImpl.PropertyInfo
6-
import kotlin.reflect.*
7-
import kotlin.reflect.full.*
4+
import kotlin.reflect.KClass
5+
import kotlin.reflect.KType
6+
import kotlin.reflect.full.isSubclassOf
7+
import kotlin.reflect.full.isSubtypeOf
8+
import kotlin.reflect.full.starProjectedType
9+
import kotlin.reflect.full.superclasses
810
import kotlin.reflect.jvm.jvmErasure
911

1012
/**
@@ -16,34 +18,24 @@ object DeserializerFactory {
1618
private val cache = mutableMapOf<KClass<*>, Deserializer>()
1719
private val typeCache = mutableMapOf<KType, Deserializer>()
1820

19-
fun getDeserializer(d: KClass<*>): Deserializer {
20-
return cache.getOrPut(d) { buildInstance(d) }
21+
fun getDeserializer(d: KClass<*>, allowSuperclasses: Boolean = true): Deserializer {
22+
return cache.getOrPut(d) {
23+
if (allowSuperclasses) {
24+
for (supers in d.superclasses)
25+
cache[supers]?.let { return@getOrPut it.forSubclass(d) }
26+
}
27+
DeserializerClassBuilder.build(d)
28+
}
2129
}
2230

23-
fun registerDeserializer(d: KClass<*>, deserializer: Deserializer, force: Boolean = false) {
31+
fun registerDeserializer(d: KClass<*>, deserializer: Deserializer) {
2432
cache[d] = deserializer
25-
val supers = d.superclasses
26-
if (supers.isEmpty())
27-
return
28-
val lastDes = if (force) null else cache[supers.last()]
29-
if (lastDes == null) {
30-
for (c in supers)
31-
cache[c] = deserializer
32-
} else {
33-
for (c in supers) {
34-
if (cache.contains(c))
35-
break
36-
cache[c] = deserializer
37-
}
38-
}
3933
}
4034

4135
fun getDeserializer(type: KType): Deserializer {
4236
return typeCache.getOrPut(type) {
4337
DeserializerPrimitiveImpl.convertType(type, null)
44-
?.let {
45-
return@getOrPut it
46-
}
38+
?.let { return@getOrPut it }
4739

4840
with(type.jvmErasure) { when {
4941
isSubclassOf(Collection::class) ->
@@ -64,56 +56,4 @@ object DeserializerFactory {
6456
throw IllegalStateException("Map key cannot be non CharSequence inherited")
6557
return value.type!!
6658
}
67-
68-
private fun buildInstance(d: KClass<*>): DeserializerClassImpl {
69-
var hasPolymorphies = false
70-
val constructorInfo = getFieldsOrder(d.constructors)
71-
val (constr, constructorFields) = constructorInfo
72-
73-
val mProperties = d.memberProperties
74-
val fieldsList = mProperties.associateTo(HashMap(mProperties.size)) { property ->
75-
val objectItemName = property.name
76-
val jsonItemName = property.findAnnotation<JsonField>()?.name
77-
?.let { t -> if(t.isNotEmpty()) t else objectItemName }
78-
?: objectItemName
79-
val p = getPropertyInfo(property, constructorFields.find { it.name == objectItemName })
80-
if (!hasPolymorphies && p.polymorphInfo != null)
81-
hasPolymorphies = true
82-
jsonItemName to p
83-
}
84-
85-
return DeserializerClassImpl(constr, fieldsList, hasPolymorphies)
86-
}
87-
88-
private fun getPropertyInfo(it: KProperty<*>, constructorParameter: KParameter?): PropertyInfo {
89-
val tType = DeserializerPrimitiveImpl.convertType(it.returnType, null)
90-
var type: DeserializerPrimitiveImpl? = null
91-
var inheritInfo: PolymorphInfo? = null
92-
var innerClass: Deserializer? = null
93-
if (tType != null) { // simple type int/string/boolean
94-
type = tType
95-
} else { // there some complex class
96-
val data = it.findAnnotation<PolymorphData>()
97-
if (data != null) { // is polymorphic
98-
val cases = mutableMapOf<Any, Deserializer>()
99-
data.strings.associateTo(cases) { it.label to getDeserializer(it.instance) }
100-
data.ints.associateTo(cases) { it.label to getDeserializer(it.instance) }
101-
inheritInfo = PolymorphInfo(data.sourceField, cases)
102-
} else {
103-
innerClass = getDeserializer(it.returnType)
104-
}
105-
}
106-
107-
return PropertyInfo(/*it.name, */it, constructorParameter, type, innerClass, inheritInfo)
108-
}
109-
110-
private fun getFieldsOrder(constructors: Collection<KFunction<*>>): Pair<KFunction<*>, List<KParameter>> {
111-
var best: KFunction<*>? = null
112-
for (c in constructors)
113-
if (best == null || c.parameters.size > best.parameters.size)
114-
best = c
115-
if (best == null)
116-
throw IllegalArgumentException("No any constructor")
117-
return best to best.parameters
118-
}
11959
}

src/iris/json/serialization/DeserializerJsonItem.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package iris.json.serialization
22

33
import iris.json.JsonItem
4+
import kotlin.reflect.KClass
45

56
/**
67
* @created 10.10.2020
@@ -10,4 +11,8 @@ class DeserializerJsonItem : Deserializer {
1011
override fun <T> deserialize(item: JsonItem): T {
1112
return item as T
1213
}
14+
15+
override fun forSubclass(d: KClass<*>): Deserializer {
16+
return this
17+
}
1318
}

src/iris/json/serialization/DeserializerMapImpl.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package iris.json.serialization
33
import iris.json.JsonEntry
44
import iris.json.JsonItem
55
import iris.json.JsonObject
6+
import kotlin.reflect.KClass
67

78
/**
89
* @created 09.10.2020
@@ -18,4 +19,8 @@ class DeserializerMapImpl(val valueDeserializer: Deserializer) : DeserializerMap
1819
override fun <T> deserialize(item: JsonItem): T {
1920
return getMap<Map<String, *>>((item as JsonObject).getEntries()) as T
2021
}
22+
23+
override fun forSubclass(d: KClass<*>): Deserializer {
24+
return this
25+
}
2126
}

0 commit comments

Comments
 (0)