@@ -10,6 +10,7 @@ import java.lang.reflect.Field
10
10
import kotlin.contracts.ExperimentalContracts
11
11
import kotlin.contracts.contract
12
12
import kotlin.math.abs
13
+ import kotlin.random.Random
13
14
import kotlin.reflect.KClass
14
15
import kotlin.reflect.KProperty
15
16
import kotlin.reflect.KProperty1
@@ -59,7 +60,8 @@ data class ProcessedDescriptorsState(
59
60
)
60
61
61
62
data class RuntimeObjectWrapper (
62
- val objectInstance : Any?
63
+ val objectInstance : Any? ,
64
+ val isRecursive : Boolean = false
63
65
) {
64
66
override fun equals (other : Any? ): Boolean {
65
67
if (other == null ) return objectInstance == null
@@ -69,11 +71,24 @@ data class RuntimeObjectWrapper(
69
71
}
70
72
71
73
override fun hashCode (): Int {
72
- return objectInstance?.hashCode() ? : 0
74
+ return if (isRecursive) Random .hashCode() else objectInstance?.hashCode() ? : 0
73
75
}
74
76
}
75
77
76
- fun Any?.toObjectWrapper (): RuntimeObjectWrapper = RuntimeObjectWrapper (this )
78
+ fun Any?.toObjectWrapper (isRecursive : Boolean = false): RuntimeObjectWrapper = RuntimeObjectWrapper (this , isRecursive)
79
+
80
+
81
+ fun Any?.getToStringValue (isRecursive : Boolean = false): String {
82
+ return if (isRecursive) {
83
+ " ${this !! ::class .simpleName} : recursive structure"
84
+ } else {
85
+ try {
86
+ this ?.toString() ? : " null"
87
+ } catch (e: StackOverflowError ) {
88
+ " ${this !! ::class .simpleName} : recursive structure"
89
+ }
90
+ }
91
+ }
77
92
78
93
/* *
79
94
* Provides contract for using threshold-based removal heuristic.
@@ -125,7 +140,8 @@ class VariablesSerializer(
125
140
" Map" ,
126
141
" Set" ,
127
142
" Collection" ,
128
- " LinkedValues"
143
+ " LinkedValues" ,
144
+ " LinkedEntrySet"
129
145
)
130
146
131
147
fun isStandardType (type : String ): Boolean = containersTypes.contains(type)
@@ -382,25 +398,27 @@ class VariablesSerializer(
382
398
it.name == propertyName
383
399
} ? : return serializedVariablesState
384
400
385
- return serializeVariableState(cellId, propertyName, property, value, false )
401
+ return serializeVariableState(cellId, propertyName, property, value, isRecursive = false , false )
386
402
}
387
403
388
404
private fun serializeVariableState (cellId : Int , name : String? , variableState : VariableState ? , isOverride : Boolean = true): SerializedVariablesState {
389
405
if (! isSerializationActive || variableState == null || name == null ) return SerializedVariablesState ()
390
- return serializeVariableState(cellId, name, variableState.property, variableState.value, isOverride)
406
+ // force recursive check
407
+ variableState.stringValue
408
+ return serializeVariableState(cellId, name, variableState.property, variableState.value.getOrNull(), variableState.isRecursive, isOverride)
391
409
}
392
410
393
- private fun serializeVariableState (cellId : Int , name : String , property : Field ? , value : Any? , isOverride : Boolean = true): SerializedVariablesState {
411
+ private fun serializeVariableState (cellId : Int , name : String , property : Field ? , value : Any? , isRecursive : Boolean , isOverride : Boolean = true): SerializedVariablesState {
394
412
val processedData = createSerializeVariableState(name, getSimpleTypeNameFrom(property, value), value)
395
- return doActualSerialization(cellId, processedData, value.toObjectWrapper() , isOverride)
413
+ return doActualSerialization(cellId, processedData, value.toObjectWrapper(isRecursive), isRecursive , isOverride)
396
414
}
397
415
398
- private fun serializeVariableState (cellId : Int , name : String , property : KProperty <* >, value : Any? , isOverride : Boolean = true): SerializedVariablesState {
416
+ private fun serializeVariableState (cellId : Int , name : String , property : KProperty <* >, value : Any? , isRecursive : Boolean , isOverride : Boolean = true): SerializedVariablesState {
399
417
val processedData = createSerializeVariableState(name, getSimpleTypeNameFrom(property, value), value)
400
- return doActualSerialization(cellId, processedData, value.toObjectWrapper() , isOverride)
418
+ return doActualSerialization(cellId, processedData, value.toObjectWrapper(isRecursive), isRecursive , isOverride)
401
419
}
402
420
403
- private fun doActualSerialization (cellId : Int , processedData : ProcessedSerializedVarsState , value : RuntimeObjectWrapper , isOverride : Boolean = true): SerializedVariablesState {
421
+ private fun doActualSerialization (cellId : Int , processedData : ProcessedSerializedVarsState , value : RuntimeObjectWrapper , isRecursive : Boolean , isOverride : Boolean = true): SerializedVariablesState {
404
422
val serializedVersion = processedData.serializedVariablesState
405
423
406
424
seenObjectsPerCell.putIfAbsent(cellId, mutableMapOf ())
@@ -428,9 +446,13 @@ class VariablesSerializer(
428
446
}
429
447
val type = processedData.propertiesType
430
448
if (type == PropertiesType .KOTLIN ) {
431
- iterateThroughContainerMembers(cellId, value.objectInstance, serializedVersion.fieldDescriptor, kProperties = currentCellDescriptors.processedSerializedVarsToKTProperties[serializedVersion])
449
+ val kProperties = currentCellDescriptors.processedSerializedVarsToKTProperties[serializedVersion]
450
+ if (kProperties?.size == 1 && kProperties.first().name == " size" ) {
451
+ serializedVersion.fieldDescriptor.addDescriptor(value.objectInstance, " data" )
452
+ }
453
+ iterateThroughContainerMembers(cellId, value.objectInstance, serializedVersion.fieldDescriptor, isRecursive = isRecursive, kProperties = currentCellDescriptors.processedSerializedVarsToKTProperties[serializedVersion])
432
454
} else {
433
- iterateThroughContainerMembers(cellId, value.objectInstance, serializedVersion.fieldDescriptor, currentCellDescriptors.processedSerializedVarsToJavaProperties[serializedVersion])
455
+ iterateThroughContainerMembers(cellId, value.objectInstance, serializedVersion.fieldDescriptor, isRecursive = isRecursive, currentCellDescriptors.processedSerializedVarsToJavaProperties[serializedVersion])
434
456
}
435
457
}
436
458
@@ -441,18 +463,19 @@ class VariablesSerializer(
441
463
cellId : Int ,
442
464
callInstance : Any? ,
443
465
descriptor : MutableFieldDescriptor ,
466
+ isRecursive : Boolean = false,
444
467
properties : PropertiesData ? = null,
445
468
kProperties : KPropertiesData ? = null,
446
469
currentDepth : Int = 0
447
470
) {
448
471
fun iterateAndStoreValues (callInstance : Any , descriptorsState : MutableMap <String , SerializedVariablesState ?>) {
449
472
if (callInstance is Collection <* >) {
450
473
callInstance.forEach {
451
- descriptorsState.addDescriptor(it)
474
+ descriptorsState.addDescriptor(it, name = it.getToStringValue() )
452
475
}
453
476
} else if (callInstance is Array <* >) {
454
477
callInstance.forEach {
455
- descriptorsState.addDescriptor(it)
478
+ descriptorsState.addDescriptor(it, name = it.getToStringValue() )
456
479
}
457
480
}
458
481
}
@@ -472,15 +495,15 @@ class VariablesSerializer(
472
495
if (currentSerializeCount > serializationLimit) {
473
496
break
474
497
}
475
- iterateThrough(it, seenObjectsPerCell, serializedIteration, descriptor, instancesPerState, callInstance)
498
+ iterateThrough(it, seenObjectsPerCell, serializedIteration, descriptor, instancesPerState, callInstance, isRecursive )
476
499
currentSerializeCount++
477
500
}
478
501
} else if (kProperties != null ) {
479
502
for (it in kProperties) {
480
503
if (currentSerializeCount > serializationLimit) {
481
504
break
482
505
}
483
- iterateThrough(it, seenObjectsPerCell, serializedIteration, descriptor, instancesPerState, callInstance)
506
+ iterateThrough(it, seenObjectsPerCell, serializedIteration, descriptor, instancesPerState, callInstance, isRecursive )
484
507
currentSerializeCount++
485
508
}
486
509
}
@@ -506,6 +529,10 @@ class VariablesSerializer(
506
529
}
507
530
}
508
531
532
+ // if (isRecursive) {
533
+ // return
534
+ // }
535
+
509
536
serializedIteration.forEach {
510
537
val serializedVariablesState = it.value.serializedVariablesState
511
538
val name = it.key
@@ -520,14 +547,15 @@ class VariablesSerializer(
520
547
else -> {
521
548
null
522
549
}
523
- }.toObjectWrapper()
550
+ }.toObjectWrapper(isRecursive )
524
551
525
552
computedDescriptorsPerCell[cellId]!! .instancesPerState + = instancesPerState
526
553
iterateThroughContainerMembers(
527
554
cellId,
528
555
neededCallInstance.objectInstance,
529
556
serializedVariablesState.fieldDescriptor,
530
- it.value.propertiesData,
557
+ isRecursive = isRecursive,
558
+ properties = it.value.propertiesData,
531
559
currentDepth = currentDepth + 1
532
560
)
533
561
}
@@ -545,17 +573,18 @@ class VariablesSerializer(
545
573
serializedIteration : MutableMap <String , ProcessedSerializedVarsState >,
546
574
descriptor : MutableFieldDescriptor ,
547
575
instancesPerState : MutableMap <SerializedVariablesState , Any ?>,
548
- callInstance : Any
576
+ callInstance : Any ,
577
+ isRecursive : Boolean = false
549
578
) {
550
579
contract {
551
580
returns() implies (elem is Field || elem is KProperty1 <* , * >)
552
581
}
553
582
554
583
val name = if (elem is Field ) elem.name else (elem as KProperty1 <Any , * >).name
555
- val value = if (elem is Field ) tryGetValueFromProperty(elem, callInstance).toObjectWrapper()
584
+ val value = if (elem is Field ) tryGetValueFromProperty(elem, callInstance).toObjectWrapper(isRecursive )
556
585
else {
557
586
elem as KProperty1 <Any , * >
558
- tryGetValueFromProperty(elem, callInstance).toObjectWrapper()
587
+ tryGetValueFromProperty(elem, callInstance).toObjectWrapper(isRecursive )
559
588
}
560
589
561
590
val simpleType = if (elem is Field ) getSimpleTypeNameFrom(elem, value.objectInstance) ? : " null"
@@ -564,6 +593,7 @@ class VariablesSerializer(
564
593
getSimpleTypeNameFrom(elem, value.objectInstance) ? : " null"
565
594
}
566
595
serializedIteration[name] = if (standardContainersUtilizer.isStandardType(simpleType)) {
596
+ // todo might add isRecursive
567
597
standardContainersUtilizer.serializeContainer(simpleType, value.objectInstance, true )
568
598
} else {
569
599
createSerializeVariableState(name, simpleType, value)
@@ -612,7 +642,7 @@ class VariablesSerializer(
612
642
if (value != null ) {
613
643
value::class .simpleName
614
644
} else {
615
- value?.toString ()
645
+ value?.getToStringValue ()
616
646
}
617
647
}
618
648
}
@@ -627,7 +657,7 @@ class VariablesSerializer(
627
657
(classifier as KClass <* >).simpleName
628
658
}
629
659
} else {
630
- value?.toString ()
660
+ value?.getToStringValue ()
631
661
}
632
662
}
633
663
@@ -742,7 +772,8 @@ fun getProperString(value: Any?): String {
742
772
743
773
val kClass = value::class
744
774
val isFromJavaArray = kClass.java.isArray
745
- try {
775
+
776
+ return try {
746
777
if (isFromJavaArray || kClass.isArray()) {
747
778
value as Array <* >
748
779
return buildString {
@@ -780,11 +811,14 @@ fun getProperString(value: Any?): String {
780
811
}
781
812
}
782
813
}
783
- } catch (e: Throwable ) {
784
814
value.toString()
815
+ } catch (e: Throwable ) {
816
+ if (e is StackOverflowError ) {
817
+ " ${value::class .simpleName} : recursive structure"
818
+ } else {
819
+ value.toString()
820
+ }
785
821
}
786
-
787
- return value.toString()
788
822
}
789
823
790
824
fun KClass <* >.isArray (): Boolean = this .isSubclassOf(Array ::class )
0 commit comments