From 45896caa6074749a3801a34e109c360b3e24e733 Mon Sep 17 00:00:00 2001 From: Nikita Zaytsev Date: Wed, 30 Jul 2025 17:57:02 +0300 Subject: [PATCH] [rdct] IJPL-170779: Fix settings synchronization for PersistentStateComponent with Element state When the state of a PersistentStateComponent is represented by an Element, a single key is used for the whole state. If all settings in the PersistentStateComponent have default values, the initial value for the key in the RdSettingsStorageService is null. However, when the settings are saved, the current state is represented by an Element that contains only a tag name. This triggers synchronization since the Json representation of such Element isn't equal to null. The fix treats the default value of a state represented by an Element as null. GitOrigin-RevId: c83ee382715d93bd14220f74e321207e69e7e987 --- .../src/StateStorageBase.kt | 21 ++++++++++++------- .../intellij/platform/settings/SettingTag.kt | 2 +- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/platform/configuration-store-impl/src/StateStorageBase.kt b/platform/configuration-store-impl/src/StateStorageBase.kt index c7aa3fd4fcf6..5de5330ffb0c 100644 --- a/platform/configuration-store-impl/src/StateStorageBase.kt +++ b/platform/configuration-store-impl/src/StateStorageBase.kt @@ -158,7 +158,7 @@ internal fun serializeState(state: Any, componentName: String, pluginId: PluginI val key = SettingDescriptor( key = createSettingKey(componentName = componentName, binding = null), pluginId = pluginId, - tags = createTags(componentName, roamingType, extraTag = null), + tags = createTags(componentName, state::class.java, roamingType, extraTag = null), serializer = JsonElementSettingSerializerDescriptor, ) @@ -191,7 +191,7 @@ internal fun serializeState(state: Any, componentName: String, pluginId: PluginI ) } else if (rootBinding is KotlinxSerializationBinding) { - val keyTags = createTags(componentName, roamingType, extraTag = null) + val keyTags = createTags(componentName, state::class.java, roamingType, extraTag = null) val key = SettingDescriptor( key = createSettingKey(componentName = componentName, binding = null), pluginId = pluginId, @@ -217,8 +217,8 @@ internal fun serializeState(state: Any, componentName: String, pluginId: PluginI } } -private fun createTags(componentName: String, roamingType: RoamingType?, extraTag: SettingTag?): List { - val componentPropertyTag = PersistenceStateComponentPropertyTag(componentName) +private fun createTags(componentName: String, stateClass: Class<*>, roamingType: RoamingType?, extraTag: SettingTag?): List { + val componentPropertyTag = PersistenceStateComponentPropertyTag(componentName, stateClass) if (roamingType == RoamingType.DISABLED) { if (extraTag == null) { return java.util.List.of(componentPropertyTag, NonShareableTag) @@ -246,7 +246,7 @@ private fun serializeWithController( controller: SettingsController, roamingType: RoamingType? ): Element? { - val keyTags = createTags(componentName, roamingType, extraTag = null) + val keyTags = createTags(componentName, state::class.java, roamingType, extraTag = null) var element: Element? = null for (binding in rootBinding.bindings!!) { val isPropertySkipped = isPropertySkipped(filter = filter, binding = binding, bean = state, rootBinding = rootBinding, isFilterPropertyItself = true) @@ -298,7 +298,7 @@ internal fun deserializeStateWithController( controller = controller, componentName = componentName, pluginId = pluginId, - tags = createTags(componentName, roamingType, extraTag = OldLocalValueSupplierTag(supplier = SynchronizedClearableLazy { + tags = createTags(componentName, stateClass, roamingType, extraTag = OldLocalValueSupplierTag(supplier = SynchronizedClearableLazy { stateElement?.let { jdomToJson(it) } @@ -331,6 +331,7 @@ internal fun deserializeStateWithController( mergeInto = null, rootBinding = rootBinding, componentName = componentName, + stateClass = stateClass, pluginId = pluginId, controller = controller, roamingType = roamingType, @@ -341,6 +342,7 @@ internal fun deserializeStateWithController( oldData = stateElement, rootBinding = rootBinding, componentName = componentName, + stateClass = stateClass, pluginId = pluginId, controller = controller, roamingType = roamingType, @@ -362,6 +364,7 @@ internal fun deserializeStateWithController( mergeInto = mergeInto, rootBinding = rootBinding as BeanBinding, componentName = componentName, + stateClass = stateClass, pluginId = pluginId, controller = controller, roamingType = roamingType, @@ -385,6 +388,7 @@ private fun getXmlSerializedState( mergeInto: T?, rootBinding: BeanBinding, componentName: String, + stateClass: Class, pluginId: PluginId, controller: SettingsController, roamingType: RoamingType?, @@ -407,7 +411,7 @@ private fun getXmlSerializedState( oldValueTagSupplier = OldLocalValueSupplierTag(oldDataSupplierLazyValue) } - val componentPropertyTag = PersistenceStateComponentPropertyTag(componentName) + val componentPropertyTag = PersistenceStateComponentPropertyTag(componentName, stateClass) val keyTags = if (roamingType == RoamingType.DISABLED) { java.util.List.of(oldValueTagSupplier, componentPropertyTag, NonShareableTag) } @@ -462,6 +466,7 @@ private fun getKotlinxSerializedState( oldData: Element?, rootBinding: KotlinxSerializationBinding, componentName: String, + stateClass: Class, pluginId: PluginId, controller: SettingsController, roamingType: RoamingType?, @@ -475,7 +480,7 @@ private fun getKotlinxSerializedState( }) } - val componentPropertyTag = PersistenceStateComponentPropertyTag(componentName) + val componentPropertyTag = PersistenceStateComponentPropertyTag(componentName, stateClass) val keyTags = if (roamingType == RoamingType.DISABLED) { java.util.List.of(oldValueTagSupplier, componentPropertyTag, NonShareableTag) } diff --git a/platform/settings/src/com/intellij/platform/settings/SettingTag.kt b/platform/settings/src/com/intellij/platform/settings/SettingTag.kt index 6bd034ce174f..9b3e6315a276 100644 --- a/platform/settings/src/com/intellij/platform/settings/SettingTag.kt +++ b/platform/settings/src/com/intellij/platform/settings/SettingTag.kt @@ -39,7 +39,7 @@ object CacheTag : SettingTag { } @Internal -class PersistenceStateComponentPropertyTag(val componentName: String) : SettingTag { +class PersistenceStateComponentPropertyTag(val componentName: String, val stateClass: Class<*>) : SettingTag { override fun toString(): String = "PersistenceStateComponentPropertyTag(componentName=$componentName)" }