Change order in SerializableProperties initialization logic
in that way so binding context would be checked only after resolve is triggered (via .getContributed descriptors). Empty binding context led to some subtle bugs. Fixes https://github.com/Kotlin/kotlinx.serialization/issues/508
This commit is contained in:
+30
-19
@@ -27,22 +27,37 @@ class SerializableProperties(private val serializableClass: ClassDescriptor, val
|
|||||||
private val primaryConstructorParameters: List<ValueParameterDescriptor> =
|
private val primaryConstructorParameters: List<ValueParameterDescriptor> =
|
||||||
serializableClass.unsubstitutedPrimaryConstructor?.valueParameters ?: emptyList()
|
serializableClass.unsubstitutedPrimaryConstructor?.valueParameters ?: emptyList()
|
||||||
|
|
||||||
private val primaryConstructorProperties: Map<PropertyDescriptor, Boolean> =
|
val serializableProperties: List<SerializableProperty>
|
||||||
primaryConstructorParameters.asSequence()
|
val isExternallySerializable: Boolean
|
||||||
.map { parameter -> bindingContext[BindingContext.VALUE_PARAMETER_AS_PROPERTY, parameter] to parameter.declaresDefaultValue() }
|
private val primaryConstructorProperties: Map<PropertyDescriptor, Boolean>
|
||||||
.mapNotNull { (a, b) -> if (a == null) null else a to b }
|
|
||||||
.toMap()
|
|
||||||
|
|
||||||
val isExternallySerializable: Boolean =
|
|
||||||
primaryConstructorParameters.size == primaryConstructorProperties.size
|
|
||||||
|
|
||||||
val serializableProperties: List<SerializableProperty> =
|
init {
|
||||||
serializableClass.unsubstitutedMemberScope.getContributedDescriptors(DescriptorKindFilter.VARIABLES)
|
val descriptorsSequence = serializableClass.unsubstitutedMemberScope.getContributedDescriptors(DescriptorKindFilter.VARIABLES)
|
||||||
.asSequence()
|
.asSequence()
|
||||||
.filterIsInstance<PropertyDescriptor>()
|
// call to any BindingContext.get should be only AFTER MemberScope.getContributedDescriptors
|
||||||
|
primaryConstructorProperties =
|
||||||
|
primaryConstructorParameters.asSequence()
|
||||||
|
.map { parameter -> bindingContext[BindingContext.VALUE_PARAMETER_AS_PROPERTY, parameter] to parameter.declaresDefaultValue() }
|
||||||
|
.mapNotNull { (a, b) -> if (a == null) null else a to b }
|
||||||
|
.toMap()
|
||||||
|
|
||||||
|
fun isPropSerializable(it: PropertyDescriptor) =
|
||||||
|
if (serializableClass.isInternalSerializable) !it.annotations.serialTransient
|
||||||
|
else !Visibilities.isPrivate(it.visibility) && ((it.isVar && !it.annotations.serialTransient) || primaryConstructorProperties.contains(
|
||||||
|
it
|
||||||
|
))
|
||||||
|
|
||||||
|
serializableProperties = descriptorsSequence.filterIsInstance<PropertyDescriptor>()
|
||||||
.filter { it.kind == CallableMemberDescriptor.Kind.DECLARATION }
|
.filter { it.kind == CallableMemberDescriptor.Kind.DECLARATION }
|
||||||
.filter(this::isPropSerializable)
|
.filter(::isPropSerializable)
|
||||||
.map { prop -> SerializableProperty(prop, primaryConstructorProperties[prop] ?: false, prop.hasBackingField(bindingContext)) }
|
.map { prop ->
|
||||||
|
SerializableProperty(
|
||||||
|
prop,
|
||||||
|
primaryConstructorProperties[prop] ?: false,
|
||||||
|
prop.hasBackingField(bindingContext)
|
||||||
|
)
|
||||||
|
}
|
||||||
.filterNot { it.transient }
|
.filterNot { it.transient }
|
||||||
.partition { primaryConstructorProperties.contains(it.descriptor) }
|
.partition { primaryConstructorProperties.contains(it.descriptor) }
|
||||||
.run {
|
.run {
|
||||||
@@ -52,12 +67,8 @@ class SerializableProperties(private val serializableClass: ClassDescriptor, val
|
|||||||
else
|
else
|
||||||
SerializableProperties(supers, bindingContext).serializableProperties + first + second
|
SerializableProperties(supers, bindingContext).serializableProperties + first + second
|
||||||
}
|
}
|
||||||
|
isExternallySerializable = primaryConstructorParameters.size == primaryConstructorProperties.size
|
||||||
private fun isPropSerializable(it: PropertyDescriptor) =
|
}
|
||||||
if (serializableClass.isInternalSerializable) !it.annotations.serialTransient
|
|
||||||
else !Visibilities.isPrivate(it.visibility) && ((it.isVar && !it.annotations.serialTransient) || primaryConstructorProperties.contains(
|
|
||||||
it
|
|
||||||
))
|
|
||||||
|
|
||||||
val serializableConstructorProperties: List<SerializableProperty> =
|
val serializableConstructorProperties: List<SerializableProperty> =
|
||||||
serializableProperties.asSequence()
|
serializableProperties.asSequence()
|
||||||
@@ -79,4 +90,4 @@ internal fun List<SerializableProperty>.bitMaskSlotCount() = size / 32 + 1
|
|||||||
internal fun bitMaskSlotAt(propertyIndex: Int) = propertyIndex / 32
|
internal fun bitMaskSlotAt(propertyIndex: Int) = propertyIndex / 32
|
||||||
|
|
||||||
internal fun BindingContext.serializablePropertiesFor(classDescriptor: ClassDescriptor): SerializableProperties =
|
internal fun BindingContext.serializablePropertiesFor(classDescriptor: ClassDescriptor): SerializableProperties =
|
||||||
this.get(SERIALIZABLE_PROPERTIES, classDescriptor) ?: SerializableProperties(classDescriptor, this)
|
this.get(SERIALIZABLE_PROPERTIES, classDescriptor) ?: SerializableProperties(classDescriptor, this)
|
||||||
|
|||||||
Reference in New Issue
Block a user