diff --git a/platform/configuration-store-impl/src/SaveSessionBase.kt b/platform/configuration-store-impl/src/SaveSessionBase.kt index 837eca66e3bc..a5c113c4c572 100644 --- a/platform/configuration-store-impl/src/SaveSessionBase.kt +++ b/platform/configuration-store-impl/src/SaveSessionBase.kt @@ -20,9 +20,6 @@ import com.intellij.openapi.util.JDOMExternalizable import com.intellij.openapi.util.WriteExternalException import com.intellij.openapi.vfs.LargeFileWriteRequestor import com.intellij.openapi.vfs.SafeWriteRequestor -import com.intellij.reference.SoftReference -import com.intellij.util.xmlb.SkipDefaultsSerializationFilter -import com.intellij.util.xmlb.XmlSerializer import org.jdom.Element abstract class SaveSessionBase : StateStorage.SaveSession, StateStorage.ExternalizationSession, SafeWriteRequestor, LargeFileWriteRequestor { @@ -46,9 +43,8 @@ abstract class SaveSessionBase : StateStorage.SaveSession, StateStorage.External protected abstract fun setSerializedState(componentName: String, element: Element?) } -private val skipDefaultsSerializationFilter = ThreadLocal>() - -fun serializeState(state: Any): Element? { +internal fun serializeState(state: Any): Element? { + @Suppress("DEPRECATION") if (state is Element) { return state } @@ -58,11 +54,6 @@ fun serializeState(state: Any): Element? { return element } else { - var serializationFilter = SoftReference.dereference(skipDefaultsSerializationFilter.get()) - if (serializationFilter == null) { - serializationFilter = SkipDefaultsSerializationFilter() - skipDefaultsSerializationFilter.set(SoftReference(serializationFilter)) - } - return XmlSerializer.serializeIfNotDefault(state, serializationFilter) + return state.serialize() } } diff --git a/platform/configuration-store-impl/src/StorageBaseEx.kt b/platform/configuration-store-impl/src/StorageBaseEx.kt index 68c0a3708424..0fe8ff6390e3 100644 --- a/platform/configuration-store-impl/src/StorageBaseEx.kt +++ b/platform/configuration-store-impl/src/StorageBaseEx.kt @@ -18,6 +18,7 @@ package com.intellij.configurationStore import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.components.PersistentStateComponent import com.intellij.openapi.util.JDOMUtil +import com.intellij.util.isEmpty import org.jdom.Element abstract class StorageBaseEx : StateStorageBase() { @@ -61,7 +62,7 @@ class StateGetter(private val component: PersistentStateCompon } else { serializeState(stateAfterLoad)?.normalizeRootName().let { - if (JDOMUtil.isEmpty(it)) null else it + if (it.isEmpty()) null else it } } diff --git a/platform/configuration-store-impl/testSrc/SchemeManagerTest.kt b/platform/configuration-store-impl/testSrc/SchemeManagerTest.kt index f081c73cbc22..616e5beffed4 100644 --- a/platform/configuration-store-impl/testSrc/SchemeManagerTest.kt +++ b/platform/configuration-store-impl/testSrc/SchemeManagerTest.kt @@ -143,7 +143,7 @@ internal class SchemeManagerTest { } fun TestScheme.save(file: Path) { - file.write(serialize().toByteArray()) + file.write(serialize()!!.toByteArray()) } @Test fun `different extensions`() { @@ -429,7 +429,7 @@ data class TestScheme(@field:com.intellij.util.xmlb.annotations.Attribute @field name = value } - override fun writeScheme() = serialize() + override fun writeScheme() = serialize()!! } open class TestSchemesProcessor : LazySchemeProcessor() { diff --git a/platform/configuration-store-impl/testSrc/StoredPropertyStateTest.kt b/platform/configuration-store-impl/testSrc/StoredPropertyStateTest.kt index 0513b79320de..f4301013d452 100644 --- a/platform/configuration-store-impl/testSrc/StoredPropertyStateTest.kt +++ b/platform/configuration-store-impl/testSrc/StoredPropertyStateTest.kt @@ -6,15 +6,17 @@ import com.intellij.util.loadElement import com.intellij.util.xmlb.annotations.Attribute import org.junit.Test -internal class AState : BaseState() { +internal class AState(languageLevel: String? = null, nestedComplex: NestedState? = null) : BaseState() { @get:Attribute("customName") - var languageLevel by storedProperty() + var languageLevel by storedProperty(languageLevel) + + var bar by string() var property2 by storedProperty(0) var floatProperty by storedProperty(0.3) - var nestedComplex by storedProperty() + var nestedComplex by storedProperty(nestedComplex) } internal class NestedState : BaseState() { @@ -37,6 +39,10 @@ class StoredPropertyStateTest { assertThat(state).isNotEqualTo(AState()) + val newEqualState = AState() + newEqualState.languageLevel = String("foo".toCharArray()) + assertThat(state).isEqualTo(newEqualState) + assertThat(state.serialize()).isEqualTo("""""") assertThat(loadElement("""""").deserialize(AState::class.java).languageLevel).isEqualTo("foo") } @@ -57,5 +63,10 @@ class StoredPropertyStateTest { state.languageLevel = null assertThat(state.modificationCount).isEqualTo(4) + + state.copyFrom(AState("foo", nestedState)) + @Suppress("USELESS_CAST") + assertThat(state.languageLevel as String?).isEqualTo("foo") + assertThat(state.modificationCount).isEqualTo(5) } } \ No newline at end of file diff --git a/platform/configuration-store-impl/testSrc/xml/XmlSerializerTest.kt b/platform/configuration-store-impl/testSrc/xml/XmlSerializerTest.kt index 01d63ad9c522..542d30aa121e 100644 --- a/platform/configuration-store-impl/testSrc/xml/XmlSerializerTest.kt +++ b/platform/configuration-store-impl/testSrc/xml/XmlSerializerTest.kt @@ -242,7 +242,7 @@ internal class XmlSerializerTest { bean.INT_V = 987 bean.STRING_V = "1234" - val element = bean.serialize() + val element = bean.serialize()!! val node = element.children.get(0) element.removeContent(node) @@ -660,8 +660,8 @@ internal class XmlSerializerTest { private val XML_PREFIX = "" internal fun assertSerializer(bean: Any, expected: String, filter: SerializationFilter?, description: String = "Serialization failure"): Element { - val element = bean.serialize(filter) - var actual = JDOMUtil.writeElement(element, "\n").trim() + val element = bean.serialize(filter, createElementIfEmpty = true)!! + var actual = JDOMUtil.writeElement(element).trim() if (!expected.startsWith(XML_PREFIX) && actual.startsWith(XML_PREFIX)) { actual = actual.substring(XML_PREFIX.length).trim() } diff --git a/platform/configuration-store-impl/testSrc/xml/XmlSerializerWithDefaultJDOMExternalizerCompatibilityTest.java b/platform/configuration-store-impl/testSrc/xml/XmlSerializerWithDefaultJDOMExternalizerCompatibilityTest.java index fe6f0b7fefd0..b275f21bcefb 100644 --- a/platform/configuration-store-impl/testSrc/xml/XmlSerializerWithDefaultJDOMExternalizerCompatibilityTest.java +++ b/platform/configuration-store-impl/testSrc/xml/XmlSerializerWithDefaultJDOMExternalizerCompatibilityTest.java @@ -3,32 +3,31 @@ package com.intellij.configurationStore.xml; import com.intellij.configurationStore.XmlSerializer; import com.intellij.openapi.util.JDOMUtil; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.util.xmlb.SerializationFilter; import com.intellij.util.xmlb.annotations.Transient; import junit.framework.TestCase; import org.jdom.Element; -import org.jetbrains.annotations.Nullable; + +import static com.intellij.testFramework.assertions.Assertions.assertThat; @SuppressWarnings({"deprecation"}) public class XmlSerializerWithDefaultJDOMExternalizerCompatibilityTest extends TestCase { public void testCompatibility() throws Exception { - final MyBean bean = new MyBean(); - assertCompatibleSerialization(bean, "MyBean"); + assertCompatibleSerialization(new MyBean()); } - private static void assertCompatibleSerialization(final Object data, final String rootTagName) throws Exception { - assertEquals(serializeWithJDom(data, rootTagName), serializeWithXmlSerializer(data)); + private static void assertCompatibleSerialization(final Object data) throws Exception { + assertThat(serializeWithJDom(data)).isEqualTo(serializeWithXmlSerializer(data)); } private static String serializeWithXmlSerializer(final Object data) throws Exception { - Element element = serialize(data, null); + Element element = serialize(data); String s = JDOMUtil.writeElement(element, "\n"); return StringUtil.trimStart(s, "").trim(); } - private static String serializeWithJDom(final Object data, String rootTagName) throws Exception { - final Element jDomRoot = new Element(rootTagName); + private static String serializeWithJDom(final Object data) throws Exception { + final Element jDomRoot = new Element("MyBean"); if (data instanceof com.intellij.openapi.util.JDOMExternalizable) { ((com.intellij.openapi.util.JDOMExternalizable)data).writeExternal(jDomRoot); @@ -37,11 +36,11 @@ public class XmlSerializerWithDefaultJDOMExternalizerCompatibilityTest extends T com.intellij.openapi.util.DefaultJDOMExternalizer.writeExternal(data, jDomRoot); } - return JDOMUtil.writeElement(jDomRoot, "\n").trim(); + return JDOMUtil.writeElement(jDomRoot).trim(); } - private static Element serialize(Object bean, @Nullable SerializationFilter filter) { - return XmlSerializer.serialize(bean, filter); + private static Element serialize(Object bean) { + return XmlSerializer.serialize(bean, null); } @SuppressWarnings("unused") diff --git a/platform/projectModel-api/src/com/intellij/openapi/components/StoredProperty.kt b/platform/projectModel-api/src/com/intellij/openapi/components/StoredProperty.kt index 1a1c3a68ee8c..b327ce5d5e21 100644 --- a/platform/projectModel-api/src/com/intellij/openapi/components/StoredProperty.kt +++ b/platform/projectModel-api/src/com/intellij/openapi/components/StoredProperty.kt @@ -20,23 +20,56 @@ import com.intellij.util.SmartList import com.intellij.util.xmlb.Accessor import com.intellij.util.xmlb.SerializationFilter import com.intellij.util.xmlb.annotations.Transient -import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty abstract class BaseState : SerializationFilter, ModificationTracker { - // if property value differs from default private val properties: MutableList = SmartList() @Volatile - internal var modificationCount: Long = 0 + @Transient + @JvmField + internal var ownModificationCount: Long = 0 // reset on load state fun resetModificationCount() { - modificationCount = 0 + ownModificationCount = 0 } protected fun incrementModificationCount() { - modificationCount++ + ownModificationCount++ + } + + fun storedProperty(defaultValue: T? = null): StoredPropertyBase { + val result = ObjectStoredProperty(defaultValue) + properties.add(result) + return result + } + + /** + * Empty string is always normalized to null. + */ + fun string(defaultValue: String? = null): StoredPropertyBase { + val result = NormalizedStringStoredProperty(defaultValue) + properties.add(result) + return result + } + + fun storedProperty(defaultValue: Int = 0): StoredPropertyBase { + val result = IntStoredProperty(defaultValue) + properties.add(result) + return result + } + + fun storedProperty(defaultValue: Float = 0f): StoredPropertyBase { + val result = FloatStoredProperty(defaultValue) + properties.add(result) + return result + } + + fun storedProperty(defaultValue: Boolean = false): StoredPropertyBase { + val result = ObjectStoredProperty(defaultValue) + properties.add(result) + return result } override fun accepts(accessor: Accessor, bean: Any): Boolean { @@ -48,42 +81,9 @@ abstract class BaseState : SerializationFilter, ModificationTracker { return false } - fun storedProperty(defaultValue: T? = null): ReadWriteProperty { - val result = ObjectStoredProperty(defaultValue) - properties.add(result) - return result - } - - /** - * Empty string is always normalized to null. - */ - fun string(defaultValue: String? = null): ReadWriteProperty { - val result = StringStoredProperty(defaultValue) - properties.add(result) - return result - } - - fun storedProperty(defaultValue: Int = 0): ReadWriteProperty { - val result = IntStoredProperty(defaultValue) - properties.add(result) - return result - } - - fun storedProperty(defaultValue: Float = 0f): ReadWriteProperty { - val result = FloatStoredProperty(defaultValue) - properties.add(result) - return result - } - - fun storedProperty(defaultValue: Boolean = false): ReadWriteProperty { - val result = ObjectStoredProperty(defaultValue) - properties.add(result) - return result - } - @Transient override fun getModificationCount(): Long { - var result = modificationCount + var result = ownModificationCount for (property in properties) { val value = property.value if (value is ModificationTracker) { @@ -112,8 +112,10 @@ abstract class BaseState : SerializationFilter, ModificationTracker { fun copyFrom(state: BaseState) { assert(state.properties.size == properties.size) + var changed = false for ((index, property) in properties.withIndex()) { val otherProperty = state.properties.get(index) + //assert(otherProperty.name == property.name) if (property.name != null) { if (otherProperty.name == null) { otherProperty.name = property.name @@ -122,37 +124,30 @@ abstract class BaseState : SerializationFilter, ModificationTracker { assert(otherProperty.name == property.name) } } - property.setValue(otherProperty) + if (property.setValue(otherProperty)) { + changed = true + } + } + + if (changed) { + incrementModificationCount() } } } -internal interface StoredProperty { - val defaultValue: Any? - val value: Any? - - var name: String? - - fun setValue(other: StoredProperty) -} - -private class ObjectStoredProperty(override val defaultValue: T) : ReadWriteProperty, StoredProperty { +private class ObjectStoredProperty(override val defaultValue: T) : StoredPropertyBase() { override var value = defaultValue - override var name: String? = null override operator fun getValue(thisRef: BaseState, property: KProperty<*>): T { name = property.name return value } - @Suppress("UNCHECKED_CAST") - override fun setValue(thisRef: BaseState, property: KProperty<*>, @Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE") newValue: T) { + override fun setValue(thisRef: BaseState, property: KProperty<*>, value: T) { name = property.name - - if (value != newValue) { - thisRef.modificationCount++ - - value = newValue + if (this.value != value) { + thisRef.ownModificationCount++ + this.value = value } } @@ -160,66 +155,71 @@ private class ObjectStoredProperty(override val defaultValue: T) : ReadWriteP override fun hashCode() = value?.hashCode() ?: 0 - override fun toString() = if (value === defaultValue) "" else value?.toString() ?: super.toString() + override fun toString() = if (value == defaultValue) "" else value?.toString() ?: super.toString() - override fun setValue(other: StoredProperty) { + override fun setValue(other: StoredProperty): Boolean { @Suppress("UNCHECKED_CAST") - value = (other as ObjectStoredProperty).value + val newValue = (other as ObjectStoredProperty).value + if (newValue == value) { + return false + } + + value = newValue + return true } } -private class StringStoredProperty(override val defaultValue: String?) : ReadWriteProperty, StoredProperty { +private class NormalizedStringStoredProperty(override val defaultValue: String?) : StoredPropertyBase() { override var value = defaultValue - override var name: String? = null override operator fun getValue(thisRef: BaseState, property: KProperty<*>): String? { name = property.name return value } - @Suppress("UNCHECKED_CAST") - override fun setValue(thisRef: BaseState, property: KProperty<*>, @Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE") _newValue: String?) { + override fun setValue(thisRef: BaseState, property: KProperty<*>, value: String?) { name = property.name - - var newValue = _newValue + var newValue = value if (newValue != null && newValue.isEmpty()) { newValue = null } - if (value != newValue) { - thisRef.modificationCount++ - value = newValue + if (this.value != newValue) { + thisRef.ownModificationCount++ + this.value = newValue } } - override fun equals(other: Any?) = this === other || (other is StringStoredProperty && value == other.value) + override fun equals(other: Any?) = this === other || (other is NormalizedStringStoredProperty && value == other.value) override fun hashCode() = value?.hashCode() ?: 0 override fun toString() = if (value == defaultValue) "" else value ?: super.toString() - override fun setValue(other: StoredProperty) { - value = (other as StringStoredProperty).value + override fun setValue(other: StoredProperty): Boolean { + val newValue = (other as NormalizedStringStoredProperty).value + if (newValue == value) { + return false + } + + value = newValue + return true } } -private class IntStoredProperty(override val defaultValue: Int) : ReadWriteProperty, StoredProperty { +private class IntStoredProperty(override val defaultValue: Int) : StoredPropertyBase() { override var value = defaultValue - override var name: String? = null override operator fun getValue(thisRef: BaseState, property: KProperty<*>): Int { name = property.name return value } - @Suppress("UNCHECKED_CAST") - override fun setValue(thisRef: BaseState, property: KProperty<*>, @Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE") newValue: Int) { + override fun setValue(thisRef: BaseState, property: KProperty<*>, value: Int) { name = property.name - - if (value != newValue) { - thisRef.modificationCount++ - - value = newValue + if (this.value != value) { + thisRef.ownModificationCount++ + this.value = value } } @@ -229,28 +229,30 @@ private class IntStoredProperty(override val defaultValue: Int) : ReadWritePrope override fun toString() = if (value == defaultValue) "" else value.toString() - override fun setValue(other: StoredProperty) { - value = (other as IntStoredProperty).value + override fun setValue(other: StoredProperty): Boolean { + val newValue = (other as IntStoredProperty).value + if (newValue == value) { + return false + } + + value = newValue + return true } } -private class FloatStoredProperty(override val defaultValue: Float) : ReadWriteProperty, StoredProperty { +private class FloatStoredProperty(override val defaultValue: Float) : StoredPropertyBase() { override var value = defaultValue - override var name: String? = null override operator fun getValue(thisRef: BaseState, property: KProperty<*>): Float { name = property.name return value } - @Suppress("UNCHECKED_CAST") - override fun setValue(thisRef: BaseState, property: KProperty<*>, @Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE") newValue: Float) { + override fun setValue(thisRef: BaseState, property: KProperty<*>, value: Float) { name = property.name - - if (value != newValue) { - thisRef.modificationCount++ - - value = newValue + if (this.value != value) { + thisRef.ownModificationCount++ + this.value = value } } @@ -260,7 +262,13 @@ private class FloatStoredProperty(override val defaultValue: Float) : ReadWriteP override fun toString() = if (value == defaultValue) "" else value.toString() - override fun setValue(other: StoredProperty) { - value = (other as FloatStoredProperty).value + override fun setValue(other: StoredProperty): Boolean { + val newValue = (other as FloatStoredProperty).value + if (newValue == value) { + return false + } + + value = newValue + return true } } \ No newline at end of file diff --git a/platform/projectModel-api/src/com/intellij/openapi/components/StoredPropertyBase.kt b/platform/projectModel-api/src/com/intellij/openapi/components/StoredPropertyBase.kt new file mode 100644 index 000000000000..d88639228abe --- /dev/null +++ b/platform/projectModel-api/src/com/intellij/openapi/components/StoredPropertyBase.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.components + +import kotlin.properties.ReadWriteProperty + +internal interface StoredProperty { + val defaultValue: Any? + val value: Any? + + var name: String? + + // true if changed + fun setValue(other: StoredProperty): Boolean +} + +// type must be exposed otherwise `provideDelegate` doesn't work +abstract class StoredPropertyBase : ReadWriteProperty, StoredProperty { + override final var name: String? = null + +// operator fun provideDelegate(thisRef: Any, property: KProperty<*>): ReadWriteProperty { +// name = property.name +// return this +// } +} \ No newline at end of file diff --git a/platform/projectModel-impl/src/com/intellij/configurationStore/xmlSerializer.kt b/platform/projectModel-impl/src/com/intellij/configurationStore/xmlSerializer.kt index 548313d0f907..e2b21fae553a 100644 --- a/platform/projectModel-impl/src/com/intellij/configurationStore/xmlSerializer.kt +++ b/platform/projectModel-impl/src/com/intellij/configurationStore/xmlSerializer.kt @@ -34,14 +34,25 @@ import kotlin.concurrent.write import kotlin.reflect.jvm.isAccessible import kotlin.reflect.primaryConstructor +private val skipDefaultsSerializationFilter = ThreadLocal>() + +private fun getDefaultSerializationFilter(): SkipDefaultsSerializationFilter { + var result = SoftReference.dereference(skipDefaultsSerializationFilter.get()) + if (result == null) { + result = SkipDefaultsSerializationFilter() + skipDefaultsSerializationFilter.set(SoftReference(result)) + } + return result +} + @JvmOverloads -fun T.serialize(filter: SerializationFilter? = SkipDefaultsSerializationFilter()): Element { +fun T.serialize(filter: SerializationFilter? = getDefaultSerializationFilter(), createElementIfEmpty: Boolean = false): Element? { try { val clazz = javaClass val binding = serializer.getClassBinding(clazz) return if (binding is BeanBinding) { // top level expects not null (null indicates error, empty element will be omitted) - binding.serialize(this, true, filter) + binding.serialize(this, createElementIfEmpty, filter) } else { binding.serialize(this, null, filter) as Element diff --git a/plugins/settings-repository/testSrc/LoadTest.kt b/plugins/settings-repository/testSrc/LoadTest.kt index d4fceb4ab6ed..4e43b7b5d9d6 100644 --- a/plugins/settings-repository/testSrc/LoadTest.kt +++ b/plugins/settings-repository/testSrc/LoadTest.kt @@ -42,7 +42,7 @@ class LoadTest : IcsTestCase() { @Test fun `load scheme`() { val localScheme = TestScheme("local") - provider.write("$dirName/local.xml", localScheme.serialize().toByteArray()) + provider.write("$dirName/local.xml", localScheme.serialize()!!.toByteArray()) val schemeManager = createSchemeManager(dirName) schemeManager.loadSchemes() @@ -58,8 +58,8 @@ class LoadTest : IcsTestCase() { assertThat(dirPath).doesNotExist() - provider.write("$dirName/local1.xml", TestScheme("local1").serialize().toByteArray()) - provider.write("$dirName/local2.xml", TestScheme("local2").serialize().toByteArray()) + provider.write("$dirName/local1.xml", TestScheme("local1").serialize()!!.toByteArray()) + provider.write("$dirName/local2.xml", TestScheme("local2").serialize()!!.toByteArray()) assertThat(dirPath.resolve("local1.xml")).isRegularFile() assertThat(dirPath.resolve("local2.xml")).isRegularFile() @@ -74,7 +74,7 @@ class LoadTest : IcsTestCase() { @Test fun `load scheme with the same names`() { val localScheme = TestScheme("local") - val data = localScheme.serialize().toByteArray() + val data = localScheme.serialize()!!.toByteArray() provider.write("$dirName/local.xml", data) provider.write("$dirName/local2.xml", data) @@ -86,12 +86,12 @@ class LoadTest : IcsTestCase() { @Test fun `load scheme from repo and read-only repo`() { val localScheme = TestScheme("local") - provider.write("$dirName/local.xml", localScheme.serialize().toByteArray()) + provider.write("$dirName/local.xml", localScheme.serialize()!!.toByteArray()) val remoteScheme = TestScheme("remote") val remoteRepository = tempDirManager.createRepository() remoteRepository - .add("$dirName/Mac OS X from RubyMine.xml", remoteScheme.serialize().toByteArray()) + .add("$dirName/Mac OS X from RubyMine.xml", remoteScheme.serialize()!!.toByteArray()) .commit("") remoteRepository.useAsReadOnlySource { @@ -114,12 +114,12 @@ class LoadTest : IcsTestCase() { val schemeName = "Emacs" val localScheme = TestScheme(schemeName, "local") - provider.write("$dirName/$schemeName.xml", localScheme.serialize().toByteArray()) + provider.write("$dirName/$schemeName.xml", localScheme.serialize()!!.toByteArray()) val remoteScheme = TestScheme(schemeName, "remote") val remoteRepository = tempDirManager.createRepository("remote") remoteRepository - .add("$dirName/$schemeName.xml", remoteScheme.serialize().toByteArray()) + .add("$dirName/$schemeName.xml", remoteScheme.serialize()!!.toByteArray()) .commit("") remoteRepository.useAsReadOnlySource {