@@ -10,23 +10,17 @@ package dev.restate.serde.kotlinx
10
10
11
11
import dev.restate.common.Slice
12
12
import dev.restate.serde.Serde
13
+ import dev.restate.serde.Serde.Schema
13
14
import dev.restate.serde.SerdeFactory
14
15
import dev.restate.serde.TypeRef
15
16
import dev.restate.serde.TypeTag
16
17
import java.nio.charset.StandardCharsets
17
18
import kotlin.reflect.KClass
18
19
import kotlin.reflect.KType
19
20
import kotlinx.serialization.*
20
- import kotlinx.serialization.builtins.*
21
- import kotlinx.serialization.descriptors.PrimitiveKind
22
- import kotlinx.serialization.descriptors.SerialDescriptor
23
- import kotlinx.serialization.descriptors.StructureKind
24
- import kotlinx.serialization.encodeToString
21
+ import kotlinx.serialization.builtins.nullable
25
22
import kotlinx.serialization.json.Json
26
- import kotlinx.serialization.json.JsonArray
27
- import kotlinx.serialization.json.JsonElement
28
23
import kotlinx.serialization.json.JsonNull
29
- import kotlinx.serialization.json.JsonTransformingSerializer
30
24
import kotlinx.serialization.modules.SerializersModule
31
25
32
26
/* *
@@ -38,7 +32,22 @@ import kotlinx.serialization.modules.SerializersModule
38
32
*/
39
33
open class KotlinSerializationSerdeFactory
40
34
@JvmOverloads
41
- constructor (private val json: Json = Json .Default ) : SerdeFactory {
35
+ constructor (
36
+ private val json: Json = Json .Default ,
37
+ private val jsonSchemaFactory: JsonSchemaFactory = DefaultJsonSchemaFactory
38
+ ) : SerdeFactory {
39
+
40
+ /* * Factory to generate json schemas. */
41
+ interface JsonSchemaFactory {
42
+ fun generateSchema (json : Json , serializer : KSerializer <* >): Schema ?
43
+
44
+ companion object {
45
+ val NOOP =
46
+ object : JsonSchemaFactory {
47
+ override fun generateSchema (json : Json , serializer : KSerializer <* >): Schema ? = null
48
+ }
49
+ }
50
+ }
42
51
43
52
@PublishedApi
44
53
internal class KtTypeTag <T >(
@@ -61,7 +70,7 @@ constructor(private val json: Json = Json.Default) : SerdeFactory {
61
70
}
62
71
val serializer: KSerializer <T > =
63
72
json.serializersModule.serializer(typeRef.type) as KSerializer <T >
64
- return jsonSerde(json, serializer)
73
+ return jsonSerde(json, jsonSchemaFactory, serializer)
65
74
}
66
75
67
76
@Suppress(" UNCHECKED_CAST" )
@@ -70,7 +79,7 @@ constructor(private val json: Json = Json.Default) : SerdeFactory {
70
79
return UNIT as Serde <T >
71
80
}
72
81
val serializer: KSerializer <T > = json.serializersModule.serializer(clazz) as KSerializer <T >
73
- return jsonSerde(json, serializer)
82
+ return jsonSerde(json, jsonSchemaFactory, serializer)
74
83
}
75
84
76
85
@Suppress(" UNCHECKED_CAST" )
@@ -81,7 +90,7 @@ constructor(private val json: Json = Json.Default) : SerdeFactory {
81
90
}
82
91
val serializer: KSerializer <T > =
83
92
json.serializersModule.serializerForKtTypeInfo(ktSerdeInfo) as KSerializer <T >
84
- return jsonSerde(json, serializer)
93
+ return jsonSerde(json, jsonSchemaFactory, serializer)
85
94
}
86
95
87
96
companion object {
@@ -103,7 +112,13 @@ constructor(private val json: Json = Json.Default) : SerdeFactory {
103
112
}
104
113
105
114
/* * Creates a [Serde] implementation using the `kotlinx.serialization` json module. */
106
- fun <T : Any ?> jsonSerde (json : Json = Json .Default , serializer : KSerializer <T >): Serde <T > {
115
+ fun <T : Any ?> jsonSerde (
116
+ json : Json = Json .Default ,
117
+ jsonSchemaFactory : JsonSchemaFactory = DefaultJsonSchemaFactory ,
118
+ serializer : KSerializer <T >
119
+ ): Serde <T > {
120
+ val schema = jsonSchemaFactory.generateSchema(json, serializer)
121
+
107
122
return object : Serde <T > {
108
123
@Suppress(" WRONG_NULLABILITY_FOR_JAVA_OVERRIDE" )
109
124
override fun serialize (value : T ? ): Slice {
@@ -123,77 +138,11 @@ constructor(private val json: Json = Json.Default) : SerdeFactory {
123
138
return " application/json"
124
139
}
125
140
126
- override fun jsonSchema (): Serde .Schema {
127
- val schema: JsonSchema = serializer.descriptor.jsonSchema()
128
- return Serde .StringifiedJsonSchema (Json .encodeToString(schema))
141
+ override fun jsonSchema (): Schema ? {
142
+ return schema
129
143
}
130
144
}
131
145
}
132
-
133
- @Serializable
134
- @PublishedApi
135
- internal data class JsonSchema (
136
- @Serializable(with = StringListSerializer ::class ) val type : List <String >? = null ,
137
- val format : String? = null ,
138
- ) {
139
- companion object {
140
- val INT = JsonSchema (type = listOf (" number" ), format = " int32" )
141
-
142
- val LONG = JsonSchema (type = listOf (" number" ), format = " int64" )
143
-
144
- val DOUBLE = JsonSchema (type = listOf (" number" ), format = " double" )
145
-
146
- val FLOAT = JsonSchema (type = listOf (" number" ), format = " float" )
147
-
148
- val STRING = JsonSchema (type = listOf (" string" ))
149
-
150
- val BOOLEAN = JsonSchema (type = listOf (" boolean" ))
151
-
152
- val OBJECT = JsonSchema (type = listOf (" object" ))
153
-
154
- val LIST = JsonSchema (type = listOf (" array" ))
155
-
156
- val ANY = JsonSchema ()
157
- }
158
- }
159
-
160
- object StringListSerializer :
161
- JsonTransformingSerializer <List <String >>(ListSerializer (String .Companion .serializer())) {
162
- override fun transformSerialize (element : JsonElement ): JsonElement {
163
- require(element is JsonArray )
164
- return element.singleOrNull() ? : element
165
- }
166
- }
167
-
168
- /* *
169
- * Super simplistic json schema generation. We should replace this with an appropriate library.
170
- */
171
- @OptIn(ExperimentalSerializationApi ::class )
172
- @PublishedApi
173
- internal fun SerialDescriptor.jsonSchema (): JsonSchema {
174
- var schema =
175
- when (this .kind) {
176
- PrimitiveKind .BOOLEAN -> JsonSchema .BOOLEAN
177
- PrimitiveKind .BYTE -> JsonSchema .INT
178
- PrimitiveKind .CHAR -> JsonSchema .STRING
179
- PrimitiveKind .DOUBLE -> JsonSchema .DOUBLE
180
- PrimitiveKind .FLOAT -> JsonSchema .FLOAT
181
- PrimitiveKind .INT -> JsonSchema .INT
182
- PrimitiveKind .LONG -> JsonSchema .LONG
183
- PrimitiveKind .SHORT -> JsonSchema .INT
184
- PrimitiveKind .STRING -> JsonSchema .STRING
185
- StructureKind .LIST -> JsonSchema .LIST
186
- StructureKind .MAP -> JsonSchema .OBJECT
187
- else -> JsonSchema .ANY
188
- }
189
-
190
- // Add nullability constraint
191
- if (this .isNullable && schema.type != null ) {
192
- schema = schema.copy(type = schema.type.plus(" null" ))
193
- }
194
-
195
- return schema
196
- }
197
146
}
198
147
199
148
@InternalSerializationApi
0 commit comments