Skip to content

Commit ab93aec

Browse files
author
Clément Petit
committed
[KT-42716] Add support for serializing property files
1 parent f833852 commit ab93aec

File tree

3 files changed

+482
-0
lines changed

3 files changed

+482
-0
lines changed

formats/properties/api/kotlinx-serialization-properties.api

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
1+
public final class kotlinx/serialization/properties/KeyValueSeparator : java/lang/Enum {
2+
public static final field COLON Lkotlinx/serialization/properties/KeyValueSeparator;
3+
public static final field EQUALS Lkotlinx/serialization/properties/KeyValueSeparator;
4+
public final fun char ()C
5+
public static fun valueOf (Ljava/lang/String;)Lkotlinx/serialization/properties/KeyValueSeparator;
6+
public static fun values ()[Lkotlinx/serialization/properties/KeyValueSeparator;
7+
}
8+
9+
public final class kotlinx/serialization/properties/LineSeparator : java/lang/Enum {
10+
public static final field CR Lkotlinx/serialization/properties/LineSeparator;
11+
public static final field CRLF Lkotlinx/serialization/properties/LineSeparator;
12+
public static final field LF Lkotlinx/serialization/properties/LineSeparator;
13+
public final fun chars ()[C
14+
public static fun valueOf (Ljava/lang/String;)Lkotlinx/serialization/properties/LineSeparator;
15+
public static fun values ()[Lkotlinx/serialization/properties/LineSeparator;
16+
}
17+
118
public abstract class kotlinx/serialization/properties/Properties : kotlinx/serialization/SerialFormat {
219
public static final field Default Lkotlinx/serialization/properties/Properties$Default;
320
public synthetic fun <init> (Lkotlinx/serialization/modules/SerializersModule;Ljava/lang/Void;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
@@ -11,8 +28,37 @@ public abstract class kotlinx/serialization/properties/Properties : kotlinx/seri
1128
public final class kotlinx/serialization/properties/Properties$Default : kotlinx/serialization/properties/Properties {
1229
}
1330

31+
public final class kotlinx/serialization/properties/PropertiesBuilder {
32+
public final fun getKeyValueSeparator ()Lkotlinx/serialization/properties/KeyValueSeparator;
33+
public final fun getLineSeparator ()Lkotlinx/serialization/properties/LineSeparator;
34+
public final fun getModule ()Lkotlinx/serialization/modules/SerializersModule;
35+
public final fun getSpacesAfterSeparator ()I
36+
public final fun getSpacesBeforeSeparator ()I
37+
public final fun setKeyValueSeparator (Lkotlinx/serialization/properties/KeyValueSeparator;)V
38+
public final fun setLineSeparator (Lkotlinx/serialization/properties/LineSeparator;)V
39+
public final fun setModule (Lkotlinx/serialization/modules/SerializersModule;)V
40+
public final fun setSpacesAfterSeparator (I)V
41+
public final fun setSpacesBeforeSeparator (I)V
42+
}
43+
1444
public final class kotlinx/serialization/properties/PropertiesKt {
1545
public static final fun Properties (Lkotlinx/serialization/modules/SerializersModule;)Lkotlinx/serialization/properties/Properties;
1646
public static final fun noImpl ()Ljava/lang/Void;
1747
}
1848

49+
public abstract class kotlinx/serialization/properties/StringProperties : kotlinx/serialization/SerialFormat {
50+
public static final field Default Lkotlinx/serialization/properties/StringProperties$Default;
51+
public synthetic fun <init> (Lkotlinx/serialization/properties/PropertiesConf;Lkotlinx/serialization/properties/Properties;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
52+
public synthetic fun <init> (Lkotlinx/serialization/properties/PropertiesConf;Lkotlinx/serialization/properties/Properties;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
53+
public final fun encodeToString (Lkotlinx/serialization/SerializationStrategy;Ljava/lang/Object;)Ljava/lang/String;
54+
public fun getSerializersModule ()Lkotlinx/serialization/modules/SerializersModule;
55+
}
56+
57+
public final class kotlinx/serialization/properties/StringProperties$Default : kotlinx/serialization/properties/StringProperties {
58+
}
59+
60+
public final class kotlinx/serialization/properties/StringPropertiesKt {
61+
public static final fun StringProperties (Lkotlin/jvm/functions/Function1;)Lkotlinx/serialization/properties/StringProperties;
62+
public static synthetic fun StringProperties$default (Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lkotlinx/serialization/properties/StringProperties;
63+
}
64+
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/*
2+
* Copyright 2017-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package kotlinx.serialization.properties
6+
7+
import kotlinx.serialization.*
8+
import kotlinx.serialization.descriptors.*
9+
import kotlinx.serialization.encoding.*
10+
import kotlinx.serialization.internal.*
11+
import kotlinx.serialization.modules.*
12+
13+
@ExperimentalSerializationApi
14+
@Suppress("UNUSED_PARAMETER")
15+
public sealed class StringProperties(
16+
private val conf: PropertiesConf,
17+
private val properties: Properties = Properties(conf.serializersModule),
18+
) : SerialFormat by properties {
19+
20+
/**
21+
* Encodes properties from the given [value] to a properties String using the given [serializer].
22+
* `null` values are omitted from the output.
23+
*/
24+
@ExperimentalSerializationApi
25+
public fun <T> encodeToString(serializer: SerializationStrategy<T>, value: T): String {
26+
val map = properties.encodeToMap(serializer, value)
27+
val builder = StringBuilder()
28+
for ((k, v) in map) {
29+
builder.append(k)
30+
repeat(conf.spacesBeforeSeparator) {
31+
builder.append(' ')
32+
}
33+
builder.append(conf.keyValueSeparator.char())
34+
repeat(conf.spacesAfterSeparator) {
35+
builder.append(' ')
36+
}
37+
builder.append(v)
38+
builder.append(conf.lineSeparator.chars())
39+
}
40+
return builder.toString()
41+
}
42+
43+
/**
44+
* A [Properties] instance that can be used as default and does not have any [SerializersModule] installed.
45+
*/
46+
@ExperimentalSerializationApi
47+
public companion object Default : StringProperties(PropertiesConf())
48+
}
49+
50+
@OptIn(ExperimentalSerializationApi::class)
51+
private class StringPropertiesImpl(conf: PropertiesConf) : StringProperties(conf)
52+
53+
/**
54+
* Creates an instance of [StringProperties] with a given [builderAction].
55+
* TODO: doc
56+
*/
57+
@ExperimentalSerializationApi
58+
public fun StringProperties(builderAction: PropertiesBuilder.() -> Unit = {}): StringProperties {
59+
val builder = PropertiesBuilder(PropertiesConf())
60+
builder.builderAction()
61+
return StringPropertiesImpl(builder.build())
62+
}
63+
64+
/**
65+
* Encodes properties from given [value] to a string using serializer for reified type [T] and returns this string.
66+
* Converts all primitive types to [String] using [toString] method.
67+
* `null` values are omitted from the output.
68+
*/
69+
@ExperimentalSerializationApi
70+
public inline fun <reified T> StringProperties.encodeToString(value: T): String =
71+
encodeToString(serializersModule.serializer(), value)
72+
73+
///**
74+
// * Decodes properties from given [propertiesString], assigns them to an object using serializer for reified type [T] and returns this object.
75+
// * [String] values are converted to respective primitive types using default conversion methods.
76+
// * [T] may contain properties of nullable types; they will be filled by non-null values from the [map], if present.
77+
// */
78+
//@ExperimentalSerializationApi
79+
//public inline fun <reified T> StringProperties.decodeFromString(propertiesString: String): T = TODO()
80+
81+
@ExperimentalSerializationApi
82+
public class PropertiesBuilder internal constructor(from: PropertiesConf) {
83+
84+
public var lineSeparator: LineSeparator = from.lineSeparator
85+
public var keyValueSeparator: KeyValueSeparator = from.keyValueSeparator
86+
public var spacesBeforeSeparator: Int = from.spacesBeforeSeparator
87+
public var spacesAfterSeparator: Int = from.spacesAfterSeparator
88+
public var module: SerializersModule = from.serializersModule
89+
90+
internal fun build(): PropertiesConf {
91+
return PropertiesConf(
92+
lineSeparator,
93+
keyValueSeparator,
94+
spacesBeforeSeparator,
95+
spacesAfterSeparator,
96+
module
97+
)
98+
}
99+
}
100+
101+
@ExperimentalSerializationApi
102+
internal data class PropertiesConf(
103+
val lineSeparator: LineSeparator = LineSeparator.LF,
104+
val keyValueSeparator: KeyValueSeparator = KeyValueSeparator.EQUALS,
105+
val spacesBeforeSeparator: Int = 0,
106+
val spacesAfterSeparator: Int = 0,
107+
val serializersModule: SerializersModule = EmptySerializersModule()
108+
)
109+
110+
@ExperimentalSerializationApi
111+
public enum class LineSeparator(private val s: String) {
112+
LF("\n"),
113+
CR("\r"),
114+
CRLF("\r\n");
115+
116+
public fun chars(): CharArray {
117+
return s.toCharArray()
118+
}
119+
}
120+
121+
@ExperimentalSerializationApi
122+
public enum class KeyValueSeparator(private val c: Char) {
123+
EQUALS('='),
124+
COLON(':');
125+
126+
public fun char(): Char = c
127+
}

0 commit comments

Comments
 (0)