@@ -2,9 +2,11 @@ package org.jetbrains.kotlinx.jupyter
22
33import org.jetbrains.kotlinx.jupyter.api.VariableState
44import org.jetbrains.kotlinx.jupyter.compiler.util.SerializedVariablesState
5+ import java.lang.reflect.Field
56import kotlin.reflect.KClass
67import kotlin.reflect.KProperty
78import kotlin.reflect.KProperty1
9+ import kotlin.reflect.KTypeParameter
810import kotlin.reflect.full.declaredMemberProperties
911import kotlin.reflect.full.isSubclassOf
1012import kotlin.reflect.jvm.isAccessible
@@ -15,8 +17,33 @@ typealias PropertiesData = Collection<KProperty1<out Any, *>>
1517
1618data class ProcessedSerializedVarsState (
1719 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+ }
2047
2148data class ProcessedDescriptorsState (
2249 // perhaps, better tp make SerializedVariablesState -> PropertiesData?
@@ -41,7 +68,6 @@ class VariablesSerializer(private val serializationStep: Int = 2, private val se
4168 */
4269 private val computedDescriptorsPerCell: MutableMap <Int , ProcessedDescriptorsState > = mutableMapOf ()
4370
44-
4571 fun serializeVariables (cellId : Int , variablesState : Map <String , VariableState >): Map <String , SerializedVariablesState > {
4672 if (seenObjectsPerCell.containsKey(cellId)) {
4773 seenObjectsPerCell[cellId]!! .clear()
@@ -62,12 +88,17 @@ class VariablesSerializer(private val serializationStep: Int = 2, private val se
6288 * @param evaluatedDescriptorsState - origin variable state to get value from
6389 * @param serializedVariablesState - current state of recursive state to go further
6490 */
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
6798 val value = evaluatedDescriptorsState.instancesPerState[serializedVariablesState]
6899 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 )
71102 }
72103 val property = propertiesData?.firstOrNull {
73104 it.name == propertyName
@@ -76,14 +107,22 @@ class VariablesSerializer(private val serializationStep: Int = 2, private val se
76107 return serializeVariableState(cellId, propertyName, property, value, false )
77108 }
78109
79-
80110 fun serializeVariableState (cellId : Int , name : String? , variableState : VariableState ? , isOverride : Boolean = true): SerializedVariablesState {
81111 if (variableState == null || name == null ) return SerializedVariablesState ()
82112 return serializeVariableState(cellId, name, variableState.property, variableState.value, isOverride)
83113 }
84114
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 {
87126 val serializedVersion = processedData.serializedVariablesState
88127
89128 seenObjectsPerCell.putIfAbsent(cellId, mutableMapOf ())
@@ -103,8 +142,7 @@ class VariablesSerializer(private val serializationStep: Int = 2, private val se
103142 return processedData.serializedVariablesState
104143 }
105144
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) {
108146 if (properties == null || callInstance == null || currentDepth >= serializationStep) return
109147
110148 val serializedIteration = mutableMapOf<String , ProcessedSerializedVarsState >()
@@ -123,7 +161,7 @@ class VariablesSerializer(private val serializationStep: Int = 2, private val se
123161 val value = tryGetValueFromProperty(it, callInstance)
124162
125163 if (! seenObjectsPerCell!! .containsKey(value)) {
126- serializedIteration[name] = createSerializeVariableState(name, it , value)
164+ serializedIteration[name] = createSerializeVariableState(name, getSimpleTypeNameFrom(it, value) , value)
127165 descriptor[name] = serializedIteration[name]!! .serializedVariablesState
128166 }
129167 if (descriptor[name] != null ) {
@@ -155,61 +193,104 @@ class VariablesSerializer(private val serializationStep: Int = 2, private val se
155193 isArrayType -> {
156194 callInstance
157195 }
158- else -> { null }
196+ else -> {
197+ null
198+ }
159199 }
160200 if (isArrayType) {
161201 if (callInstance is List <* >) {
162202 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+ )
165210 }
166211 } else {
167212 callInstance as Array <* >
168213 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+ )
171221 }
172222 }
173223
174224 return @forEach
175225 }
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+ )
178239 }
179240 }
180241 }
181242
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+ }
182251
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 ) {
185254 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+ }
188261 } else {
189262 value?.toString()
190263 }
264+ }
191265
266+ private fun createSerializeVariableState (name : String , simpleTypeName : String? , value : Any? ): ProcessedSerializedVarsState {
192267 // make it exception-safe
193268 val membersProperties = try {
194269 if (value != null ) value::class .declaredMemberProperties else null
195270 } catch (e: Throwable ) {
196271 null
197272 }
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) {
200282 " Array"
201283 } else if (isContainer && value is List <* >) {
202284 " SingletonList"
203285 } else {
204- simpleName .toString()
286+ simpleTypeName .toString()
205287 }
206288
207289 val serializedVariablesState = SerializedVariablesState (name, type, getProperString(value), isContainer)
208290
209- return ProcessedSerializedVarsState (serializedVariablesState, membersProperties)
291+ return ProcessedSerializedVarsState (serializedVariablesState, membersProperties, jvmFields )
210292 }
211293
212-
213294 private fun tryGetValueFromProperty (property : KProperty1 <Any , * >, callInstance : Any ): Any? {
214295 // some fields may be optimized out like array size. Thus, calling it.isAccessible would return error
215296 val canAccess = try {
@@ -243,13 +324,10 @@ class VariablesSerializer(private val serializationStep: Int = 2, private val se
243324 false
244325 }
245326 }
246-
247327}
248328
249- // TODO: maybe think of considering the depth?
250329fun 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? ) {
253331 if (index != containerSize - 1 ) {
254332 builder.append(value, " , " )
255333 } else {
@@ -296,4 +374,4 @@ fun getProperString(value: Any?): String {
296374 }
297375
298376 return value.toString()
299- }
377+ }
0 commit comments