From 62af21d9f773f30c2085fa26a11fe5bf43b2d722 Mon Sep 17 00:00:00 2001 From: Karol Lewandowski Date: Thu, 12 Oct 2023 10:52:09 +0200 Subject: [PATCH] persisting_state_of_components.md: Add information about Kotlin persistent state class implementation --- .../basics/persisting_state_of_components.md | 51 ++++++++++++++++--- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/topics/basics/persisting_state_of_components.md b/topics/basics/persisting_state_of_components.md index 280af8e7d..1ea38b9a8 100644 --- a/topics/basics/persisting_state_of_components.md +++ b/topics/basics/persisting_state_of_components.md @@ -25,14 +25,40 @@ If an extension needs to have a persistent state, define a separate service resp ### Implementing the PersistentStateComponent Interface -The implementation of `PersistentStateComponent` needs to be parameterized with the type of state class. + + + +The easiest way to implement a persistent state component in Kotlin is extending [`SimplePersistentStateComponent`](%gh-ic%/platform/projectModel-api/src/com/intellij/openapi/components/SimplePersistentStateComponent.kt), which implements `PersistentStateComponent`. + +`SimplePersistentStateComponent` is parameterized by a subclass of [`BaseState`](%gh-ic%/platform/projectModel-api/src/com/intellij/openapi/components/BaseState.kt). +`BaseState` provides set of handy [property delegates](https://kotlinlang.org/docs/delegated-properties.html), which make it easy to create properties with default values. +In addition, delegates track property modifications internally, which help decrease calling `PersistentStateComponent.getState()` by the platform. + +It is recommended to create a separate classes for a component and its state: + +```kotlin +@State(...) +class MySettings : SimplePersistentStateComponent(MyState()) + +class MyState : BaseState() { + var value by string() +} +``` + + + + +The implementation of `PersistentStateComponent` must be parameterized with the type of state class. The state class can either be a separate class, or the class implementing `PersistentStateComponent`. -In the former case, the state class instance is typically stored as a field in the `PersistentStateComponent` class: + + +In this case, the state class instance is typically stored as a field in the `PersistentStateComponent` class. +When the state is loaded from the storage, it is assigned to the state field (see `loadState()`): ```java @State(...) -class MyService implements PersistentStateComponent { +class MySettings implements PersistentStateComponent { static class State { public String value; @@ -50,24 +76,35 @@ class MyService implements PersistentStateComponent { } ``` -In the latter case, use the following pattern to implement `getState()` and `loadState()` methods: +Using a separate state class is the recommended approach. + + + + + +In this case, `getState()` returns the component itself, and `loadState()` copies properties of the state loaded from storage to the component instance: ```java @State(...) -class MyService implements PersistentStateComponent { +class MySettings implements PersistentStateComponent { public String stateValue; - public MyService getState() { + public MySettings getState() { return this; } - public void loadState(MyService state) { + public void loadState(MySettings state) { XmlSerializerUtil.copyBean(state, this); } } ``` + + + + + ### Implementing the State Class The implementation of `PersistentStateComponent` works by serializing public fields, [annotated](%gh-ic%/platform/util/src/com/intellij/util/xmlb/annotations) private fields (see also [Customizing the XML format of persisted values](#customizing-the-xml-format-of-persisted-values)), and bean properties into an XML format.