@@ -2,9 +2,11 @@ package org.jetbrains.kotlinx.jupyter
2
2
3
3
import org.jetbrains.kotlinx.jupyter.api.VariableState
4
4
import org.jetbrains.kotlinx.jupyter.compiler.util.SerializedVariablesState
5
+ import java.lang.reflect.Field
5
6
import kotlin.reflect.KClass
6
7
import kotlin.reflect.KProperty
7
8
import kotlin.reflect.KProperty1
9
+ import kotlin.reflect.KTypeParameter
8
10
import kotlin.reflect.full.declaredMemberProperties
9
11
import kotlin.reflect.full.isSubclassOf
10
12
import kotlin.reflect.jvm.isAccessible
@@ -15,8 +17,33 @@ typealias PropertiesData = Collection<KProperty1<out Any, *>>
15
17
16
18
data class ProcessedSerializedVarsState (
17
19
val serializedVariablesState : SerializedVariablesState ,
18
- val propertiesData : PropertiesData ?
19
- )
20
+ val propertiesData : PropertiesData ? ,
21
+ val jvmOnlyFields : Array <Field >? = null
22
+ ) {
23
+ // autogenerated
24
+ override fun equals (other : Any? ): Boolean {
25
+ if (this == = other) return true
26
+ if (javaClass != other?.javaClass) return false
27
+
28
+ other as ProcessedSerializedVarsState
29
+
30
+ if (serializedVariablesState != other.serializedVariablesState) return false
31
+ if (propertiesData != other.propertiesData) return false
32
+ if (jvmOnlyFields != null ) {
33
+ if (other.jvmOnlyFields == null ) return false
34
+ if (! jvmOnlyFields.contentEquals(other.jvmOnlyFields)) return false
35
+ } else if (other.jvmOnlyFields != null ) return false
36
+
37
+ return true
38
+ }
39
+
40
+ override fun hashCode (): Int {
41
+ var result = serializedVariablesState.hashCode()
42
+ result = 31 * result + (propertiesData?.hashCode() ? : 0 )
43
+ result = 31 * result + (jvmOnlyFields?.contentHashCode() ? : 0 )
44
+ return result
45
+ }
46
+ }
20
47
21
48
data class ProcessedDescriptorsState (
22
49
// perhaps, better tp make SerializedVariablesState -> PropertiesData?
@@ -41,7 +68,6 @@ class VariablesSerializer(private val serializationStep: Int = 2, private val se
41
68
*/
42
69
private val computedDescriptorsPerCell: MutableMap <Int , ProcessedDescriptorsState > = mutableMapOf ()
43
70
44
-
45
71
fun serializeVariables (cellId : Int , variablesState : Map <String , VariableState >): Map <String , SerializedVariablesState > {
46
72
if (seenObjectsPerCell.containsKey(cellId)) {
47
73
seenObjectsPerCell[cellId]!! .clear()
@@ -62,12 +88,17 @@ class VariablesSerializer(private val serializationStep: Int = 2, private val se
62
88
* @param evaluatedDescriptorsState - origin variable state to get value from
63
89
* @param serializedVariablesState - current state of recursive state to go further
64
90
*/
65
- private fun updateVariableState (cellId : Int , propertyName : String , evaluatedDescriptorsState : ProcessedDescriptorsState ,
66
- serializedVariablesState : SerializedVariablesState ): SerializedVariablesState {
91
+ private fun updateVariableState (
92
+ cellId : Int ,
93
+ propertyName : String ,
94
+ evaluatedDescriptorsState : ProcessedDescriptorsState ,
95
+ serializedVariablesState : SerializedVariablesState
96
+ ): SerializedVariablesState {
97
+ // TODO: consider anonymous class as well and fix bug with state
67
98
val value = evaluatedDescriptorsState.instancesPerState[serializedVariablesState]
68
99
val propertiesData = evaluatedDescriptorsState.processedSerializedVarsState[serializedVariablesState]
69
- if (propertiesData == null && value != null && value::class .java.isArray) {
70
- return serializeVariableState(cellId, propertyName, null , value, false )
100
+ if (propertiesData == null && value != null && ( value::class .java.isArray || value:: class .java.isMemberClass) ) {
101
+ return serializeVariableState(cellId, propertyName, propertiesData , value, false )
71
102
}
72
103
val property = propertiesData?.firstOrNull {
73
104
it.name == propertyName
@@ -76,14 +107,22 @@ class VariablesSerializer(private val serializationStep: Int = 2, private val se
76
107
return serializeVariableState(cellId, propertyName, property, value, false )
77
108
}
78
109
79
-
80
110
fun serializeVariableState (cellId : Int , name : String? , variableState : VariableState ? , isOverride : Boolean = true): SerializedVariablesState {
81
111
if (variableState == null || name == null ) return SerializedVariablesState ()
82
112
return serializeVariableState(cellId, name, variableState.property, variableState.value, isOverride)
83
113
}
84
114
85
- fun serializeVariableState (cellId : Int , name : String , property : KProperty <* >? , value : Any? , isOverride : Boolean = true): SerializedVariablesState {
86
- val processedData = createSerializeVariableState(name, property, value)
115
+ fun serializeVariableState (cellId : Int , name : String , property : Field ? , value : Any? , isOverride : Boolean = true): SerializedVariablesState {
116
+ val processedData = createSerializeVariableState(name, getSimpleTypeNameFrom(property, value), value)
117
+ return doActualSerialization(cellId, processedData, value, isOverride)
118
+ }
119
+
120
+ fun serializeVariableState (cellId : Int , name : String , property : KProperty <* >, value : Any? , isOverride : Boolean = true): SerializedVariablesState {
121
+ val processedData = createSerializeVariableState(name, getSimpleTypeNameFrom(property, value), value)
122
+ return doActualSerialization(cellId, processedData, value, isOverride)
123
+ }
124
+
125
+ private fun doActualSerialization (cellId : Int , processedData : ProcessedSerializedVarsState , value : Any? , isOverride : Boolean = true): SerializedVariablesState {
87
126
val serializedVersion = processedData.serializedVariablesState
88
127
89
128
seenObjectsPerCell.putIfAbsent(cellId, mutableMapOf ())
@@ -103,8 +142,7 @@ class VariablesSerializer(private val serializationStep: Int = 2, private val se
103
142
return processedData.serializedVariablesState
104
143
}
105
144
106
-
107
- private fun iterateThroughContainerMembers (cellId : Int , callInstance : Any? , descriptor : MutableFieldDescriptor , properties : PropertiesData ? , currentDepth : Int = 0): Unit {
145
+ private fun iterateThroughContainerMembers (cellId : Int , callInstance : Any? , descriptor : MutableFieldDescriptor , properties : PropertiesData ? , currentDepth : Int = 0) {
108
146
if (properties == null || callInstance == null || currentDepth >= serializationStep) return
109
147
110
148
val serializedIteration = mutableMapOf<String , ProcessedSerializedVarsState >()
@@ -123,7 +161,7 @@ class VariablesSerializer(private val serializationStep: Int = 2, private val se
123
161
val value = tryGetValueFromProperty(it, callInstance)
124
162
125
163
if (! seenObjectsPerCell!! .containsKey(value)) {
126
- serializedIteration[name] = createSerializeVariableState(name, it , value)
164
+ serializedIteration[name] = createSerializeVariableState(name, getSimpleTypeNameFrom(it, value) , value)
127
165
descriptor[name] = serializedIteration[name]!! .serializedVariablesState
128
166
}
129
167
if (descriptor[name] != null ) {
@@ -155,61 +193,104 @@ class VariablesSerializer(private val serializationStep: Int = 2, private val se
155
193
isArrayType -> {
156
194
callInstance
157
195
}
158
- else -> { null }
196
+ else -> {
197
+ null
198
+ }
159
199
}
160
200
if (isArrayType) {
161
201
if (callInstance is List <* >) {
162
202
callInstance.forEach { arrayElem ->
163
- iterateThroughContainerMembers(cellId, arrayElem, serializedVariablesState.fieldDescriptor,
164
- it.value.propertiesData, currentDepth + 1 )
203
+ iterateThroughContainerMembers(
204
+ cellId,
205
+ arrayElem,
206
+ serializedVariablesState.fieldDescriptor,
207
+ it.value.propertiesData,
208
+ currentDepth + 1
209
+ )
165
210
}
166
211
} else {
167
212
callInstance as Array <* >
168
213
callInstance.forEach { arrayElem ->
169
- iterateThroughContainerMembers(cellId, arrayElem, serializedVariablesState.fieldDescriptor,
170
- it.value.propertiesData, currentDepth + 1 )
214
+ iterateThroughContainerMembers(
215
+ cellId,
216
+ arrayElem,
217
+ serializedVariablesState.fieldDescriptor,
218
+ it.value.propertiesData,
219
+ currentDepth + 1
220
+ )
171
221
}
172
222
}
173
223
174
224
return @forEach
175
225
}
176
- iterateThroughContainerMembers(cellId, neededCallInstance, serializedVariablesState.fieldDescriptor,
177
- it.value.propertiesData, currentDepth + 1 )
226
+
227
+ // update state with JVMFields
228
+ it.value.jvmOnlyFields?.forEach { field ->
229
+ serializedVariablesState.fieldDescriptor[field.name] = serializeVariableState(cellId, field.name, field, neededCallInstance)
230
+ instancesPerState[serializedVariablesState] = neededCallInstance
231
+ }
232
+ iterateThroughContainerMembers(
233
+ cellId,
234
+ neededCallInstance,
235
+ serializedVariablesState.fieldDescriptor,
236
+ it.value.propertiesData,
237
+ currentDepth + 1
238
+ )
178
239
}
179
240
}
180
241
}
181
242
243
+ private fun getSimpleTypeNameFrom (property : Field ? , value : Any? ): String? {
244
+ return if (property != null ) {
245
+ val returnType = property.type
246
+ returnType.simpleName
247
+ } else {
248
+ value?.toString()
249
+ }
250
+ }
182
251
183
- private fun createSerializeVariableState ( name : String , property : KProperty <* >? , value : Any? ): ProcessedSerializedVarsState {
184
- val simpleName = if (property != null ) {
252
+ private fun getSimpleTypeNameFrom ( property : KProperty <* >? , value : Any? ): String? {
253
+ return if (property != null ) {
185
254
val returnType = property.returnType
186
- val classifier = returnType.classifier as KClass <* >
187
- classifier.simpleName
255
+ val classifier = returnType.classifier
256
+ if (classifier is KTypeParameter ) {
257
+ classifier.name
258
+ } else {
259
+ (classifier as KClass <* >).simpleName
260
+ }
188
261
} else {
189
262
value?.toString()
190
263
}
264
+ }
191
265
266
+ private fun createSerializeVariableState (name : String , simpleTypeName : String? , value : Any? ): ProcessedSerializedVarsState {
192
267
// make it exception-safe
193
268
val membersProperties = try {
194
269
if (value != null ) value::class .declaredMemberProperties else null
195
270
} catch (e: Throwable ) {
196
271
null
197
272
}
198
- val isContainer = if (membersProperties != null ) (membersProperties.size > 1 || value!! ::class .java.isArray) else false
199
- val type = if (value!= null && value::class .java.isArray) {
273
+ val javaClass = value?.javaClass
274
+ val jvmFields = if (javaClass != null && javaClass.isMemberClass) {
275
+ javaClass.declaredFields
276
+ } else { null }
277
+
278
+ val isContainer = if (membersProperties != null ) (
279
+ membersProperties.isNotEmpty() || value!! ::class .java.isArray || (javaClass != null && javaClass.isMemberClass)
280
+ ) else false
281
+ val type = if (value != null && value::class .java.isArray) {
200
282
" Array"
201
283
} else if (isContainer && value is List <* >) {
202
284
" SingletonList"
203
285
} else {
204
- simpleName .toString()
286
+ simpleTypeName .toString()
205
287
}
206
288
207
289
val serializedVariablesState = SerializedVariablesState (name, type, getProperString(value), isContainer)
208
290
209
- return ProcessedSerializedVarsState (serializedVariablesState, membersProperties)
291
+ return ProcessedSerializedVarsState (serializedVariablesState, membersProperties, jvmFields )
210
292
}
211
293
212
-
213
294
private fun tryGetValueFromProperty (property : KProperty1 <Any , * >, callInstance : Any ): Any? {
214
295
// some fields may be optimized out like array size. Thus, calling it.isAccessible would return error
215
296
val canAccess = try {
@@ -243,13 +324,10 @@ class VariablesSerializer(private val serializationStep: Int = 2, private val se
243
324
false
244
325
}
245
326
}
246
-
247
327
}
248
328
249
- // TODO: maybe think of considering the depth?
250
329
fun getProperString (value : Any? ): String {
251
-
252
- fun print (builder : StringBuilder , containerSize : Int , index : Int , value : Any? ): Unit {
330
+ fun print (builder : StringBuilder , containerSize : Int , index : Int , value : Any? ) {
253
331
if (index != containerSize - 1 ) {
254
332
builder.append(value, " , " )
255
333
} else {
@@ -296,4 +374,4 @@ fun getProperString(value: Any?): String {
296
374
}
297
375
298
376
return value.toString()
299
- }
377
+ }
0 commit comments