-
Notifications
You must be signed in to change notification settings - Fork 620
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Generator for .proto files based on serializable Kotlin classes (#1255)
Fixes #34 Co-authored-by: Vsevolod Tolstopyatov <qwwdfsad@gmail.com>
- Loading branch information
Showing
21 changed files
with
1,484 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
511 changes: 511 additions & 0 deletions
511
.../protobuf/commonMain/src/kotlinx/serialization/protobuf/schema/ProtoBufSchemaGenerator.kt
Large diffs are not rendered by default.
Oops, something went wrong.
115 changes: 115 additions & 0 deletions
115
...ts/protobuf/commonTest/src/kotlinx/serialization/protobuf/schema/SchemaValidationsTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
package kotlinx.serialization.protobuf.schema | ||
|
||
import kotlinx.serialization.* | ||
import kotlinx.serialization.protobuf.ProtoNumber | ||
import kotlin.test.Test | ||
import kotlin.test.assertFailsWith | ||
|
||
class SchemaValidationsTest { | ||
@Serializable | ||
data class ValidClass(val i: Int) | ||
|
||
@Serializable | ||
@SerialName("ValidClass") | ||
data class DuplicateClass(val l: Long) | ||
|
||
@Serializable | ||
@SerialName("invalid serial name") | ||
data class InvalidClassName(val i: Int) | ||
|
||
@Serializable | ||
data class InvalidClassFieldName(@SerialName("invalid serial name") val i: Int) | ||
|
||
@Serializable | ||
data class FieldNumberDuplicates(@ProtoNumber(42) val i: Int, @ProtoNumber(42) val j: Int) | ||
|
||
@Serializable | ||
data class FieldNumberImplicitlyDuplicates(@ProtoNumber(2) val i: Int, val j: Int) | ||
|
||
@Serializable | ||
@SerialName("invalid serial name") | ||
enum class InvalidEnumName { SINGLETON } | ||
|
||
@Serializable | ||
enum class InvalidEnumElementName { | ||
FIRST, | ||
|
||
@SerialName("invalid serial name") | ||
SECOND | ||
} | ||
|
||
|
||
@Test | ||
fun testInvalidEnumElementSerialName() { | ||
val descriptors = listOf(InvalidEnumElementName.serializer().descriptor) | ||
assertFailsWith(IllegalArgumentException::class) { ProtoBufSchemaGenerator.generateSchemaText(descriptors) } | ||
} | ||
|
||
@Test | ||
fun testInvalidClassSerialName() { | ||
val descriptors = listOf(InvalidClassName.serializer().descriptor) | ||
assertFailsWith(IllegalArgumentException::class) { ProtoBufSchemaGenerator.generateSchemaText(descriptors) } | ||
} | ||
|
||
@Test | ||
fun testInvalidClassFieldSerialName() { | ||
val descriptors = listOf(InvalidClassFieldName.serializer().descriptor) | ||
assertFailsWith(IllegalArgumentException::class) { ProtoBufSchemaGenerator.generateSchemaText(descriptors) } | ||
} | ||
|
||
@Test | ||
fun testDuplicateSerialNames() { | ||
val descriptors = listOf(InvalidClassFieldName.serializer().descriptor) | ||
assertFailsWith(IllegalArgumentException::class) { ProtoBufSchemaGenerator.generateSchemaText(descriptors) } | ||
} | ||
|
||
@Test | ||
fun testInvalidEnumSerialName() { | ||
val descriptors = listOf(InvalidEnumName.serializer().descriptor) | ||
assertFailsWith(IllegalArgumentException::class) { ProtoBufSchemaGenerator.generateSchemaText(descriptors) } | ||
} | ||
|
||
@Test | ||
fun testDuplicationSerialName() { | ||
val descriptors = listOf(ValidClass.serializer().descriptor, DuplicateClass.serializer().descriptor) | ||
assertFailsWith(IllegalArgumentException::class) { ProtoBufSchemaGenerator.generateSchemaText(descriptors) } | ||
} | ||
|
||
@Test | ||
fun testInvalidOptionName() { | ||
val descriptors = listOf(ValidClass.serializer().descriptor) | ||
assertFailsWith(IllegalArgumentException::class) { | ||
ProtoBufSchemaGenerator.generateSchemaText( | ||
descriptors, | ||
options = mapOf("broken name" to "value") | ||
) | ||
} | ||
} | ||
|
||
@Test | ||
fun testIllegalPackageNames() { | ||
val descriptors = listOf(ValidClass.serializer().descriptor) | ||
assertFailsWith(IllegalArgumentException::class) { ProtoBufSchemaGenerator.generateSchemaText(descriptors, "") } | ||
assertFailsWith(IllegalArgumentException::class) { ProtoBufSchemaGenerator.generateSchemaText(descriptors, ".") } | ||
assertFailsWith(IllegalArgumentException::class) { ProtoBufSchemaGenerator.generateSchemaText(descriptors, ".first.dot") } | ||
assertFailsWith(IllegalArgumentException::class) { ProtoBufSchemaGenerator.generateSchemaText(descriptors, "ended.with.dot.") } | ||
assertFailsWith(IllegalArgumentException::class) { ProtoBufSchemaGenerator.generateSchemaText(descriptors, "first._underscore") } | ||
assertFailsWith(IllegalArgumentException::class) { ProtoBufSchemaGenerator.generateSchemaText(descriptors, "first.1digit") } | ||
assertFailsWith(IllegalArgumentException::class) { ProtoBufSchemaGenerator.generateSchemaText(descriptors, "illegal.sym+bol") } | ||
} | ||
|
||
@Test | ||
fun testValidPackageNames() { | ||
val descriptors = listOf(ValidClass.serializer().descriptor) | ||
ProtoBufSchemaGenerator.generateSchemaText(descriptors, "singleIdent") | ||
ProtoBufSchemaGenerator.generateSchemaText(descriptors, "double.ident") | ||
ProtoBufSchemaGenerator.generateSchemaText(descriptors, "with.digits0123") | ||
ProtoBufSchemaGenerator.generateSchemaText(descriptors, "with.underscore_") | ||
} | ||
|
||
@Test | ||
fun testFieldNumberDuplicates() { | ||
assertFailsWith(IllegalArgumentException::class) { ProtoBufSchemaGenerator.generateSchemaText(listOf(FieldNumberDuplicates.serializer().descriptor)) } | ||
assertFailsWith(IllegalArgumentException::class) { ProtoBufSchemaGenerator.generateSchemaText(listOf(FieldNumberImplicitlyDuplicates.serializer().descriptor)) } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
syntax = "proto2"; | ||
|
||
package kotlinx.serialization.protobuf.schema.generator; | ||
|
||
// serial name 'kotlinx.serialization.protobuf.schema.GenerationTest.AbstractHolder' | ||
message AbstractHolder { | ||
required KotlinxSerializationPolymorphic abs = 1; | ||
} | ||
|
||
// This message was generated to support polymorphic types and does not present in Kotlin. | ||
message KotlinxSerializationPolymorphic { | ||
required string type = 1; | ||
required bytes value = 2; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
syntax = "proto2"; | ||
|
||
package kotlinx.serialization.protobuf.schema.generator; | ||
|
||
// serial name 'kotlinx.serialization.protobuf.schema.GenerationTest.ContextualHolder' | ||
message ContextualHolder { | ||
required bytes value = 1; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
syntax = "proto2"; | ||
|
||
package kotlinx.serialization.protobuf.schema.generator; | ||
|
||
// serial name 'kotlinx.serialization.protobuf.schema.GenerationTest.FieldNumberClass' | ||
message FieldNumberClass { | ||
required int32 a = 1; | ||
required int32 b = 5; | ||
required int32 c = 3; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
syntax = "proto2"; | ||
|
||
package kotlinx.serialization.protobuf.schema.generator; | ||
|
||
// serial name 'kotlinx.serialization.protobuf.schema.GenerationTest.LegacyMapHolder' | ||
message LegacyMapHolder { | ||
repeated LegacyMapHolder_keyAsMessage keyAsMessage = 1; | ||
repeated LegacyMapHolder_keyAsEnum keyAsEnum = 2; | ||
repeated LegacyMapHolder_keyAsBytes keyAsBytes = 3; | ||
repeated LegacyMapHolder_keyAsList keyAsList = 4; | ||
repeated LegacyMapHolder_keyAsDeepList keyAsDeepList = 5; | ||
repeated LegacyMapHolder_nullableKeyAndValue nullableKeyAndValue = 6; | ||
} | ||
|
||
// This message was generated to support legacy map and does not present in Kotlin. | ||
// Containing message 'LegacyMapHolder', field 'keyAsMessage' | ||
message LegacyMapHolder_keyAsMessage { | ||
required OptionsClass key = 1; | ||
required int32 value = 2; | ||
} | ||
|
||
// This message was generated to support legacy map and does not present in Kotlin. | ||
// Containing message 'LegacyMapHolder', field 'keyAsEnum' | ||
message LegacyMapHolder_keyAsEnum { | ||
required OverriddenEnumName key = 1; | ||
required OptionsClass value = 2; | ||
} | ||
|
||
// This message was generated to support legacy map and does not present in Kotlin. | ||
// Containing message 'LegacyMapHolder', field 'keyAsBytes' | ||
message LegacyMapHolder_keyAsBytes { | ||
required bytes key = 1; | ||
required bytes value = 2; | ||
} | ||
|
||
// This message was generated to support legacy map and does not present in Kotlin. | ||
// Containing message 'LegacyMapHolder', field 'keyAsList' | ||
message LegacyMapHolder_keyAsList { | ||
repeated int32 key = 1; | ||
required bytes value = 2; | ||
} | ||
|
||
// This message was generated to support legacy map and does not present in Kotlin. | ||
// Containing message 'LegacyMapHolder', field 'keyAsDeepList' | ||
message LegacyMapHolder_keyAsDeepList { | ||
repeated LegacyMapHolder_keyAsDeepList_key key = 1; | ||
required bytes value = 2; | ||
} | ||
|
||
// This message was generated to support legacy map and does not present in Kotlin. | ||
// Containing message 'LegacyMapHolder', field 'nullableKeyAndValue' | ||
message LegacyMapHolder_nullableKeyAndValue { | ||
required OptionsClass key = 1; | ||
required OptionsClass value = 2; | ||
} | ||
|
||
// serial name 'kotlinx.serialization.protobuf.schema.GenerationTest.OptionsClass' | ||
message OptionsClass { | ||
required int32 i = 1; | ||
} | ||
|
||
enum OverriddenEnumName { | ||
FIRST = 0; | ||
OverriddenElementName = 1; | ||
} | ||
|
||
// This message was generated to support nested collection in list and does not present in Kotlin. | ||
// Containing message 'LegacyMapHolder', field 'keyAsDeepList' | ||
message LegacyMapHolder_keyAsDeepList_key { | ||
repeated int32 value = 1; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
syntax = "proto2"; | ||
|
||
package kotlinx.serialization.protobuf.schema.generator; | ||
|
||
// serial name 'kotlinx.serialization.protobuf.schema.GenerationTest.ListClass' | ||
message ListClass { | ||
repeated int32 intList = 1; | ||
repeated int32 intArray = 2; | ||
// WARNING: nullable elements of collections can not be represented in protobuf | ||
repeated int32 boxedIntArray = 3; | ||
repeated OptionsClass messageList = 4; | ||
repeated OverriddenEnumName enumList = 5; | ||
} | ||
|
||
// serial name 'kotlinx.serialization.protobuf.schema.GenerationTest.OptionsClass' | ||
message OptionsClass { | ||
required int32 i = 1; | ||
} | ||
|
||
enum OverriddenEnumName { | ||
FIRST = 0; | ||
OverriddenElementName = 1; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
syntax = "proto2"; | ||
|
||
package kotlinx.serialization.protobuf.schema.generator; | ||
|
||
// serial name 'kotlinx.serialization.protobuf.schema.GenerationTest.MapClass' | ||
message MapClass { | ||
map<int32, float> scalarMap = 1; | ||
map<int32, bytes> bytesMap = 2; | ||
map<string, OptionsClass> messageMap = 3; | ||
map<bool, OverriddenEnumName> enumMap = 4; | ||
} | ||
|
||
// serial name 'kotlinx.serialization.protobuf.schema.GenerationTest.OptionsClass' | ||
message OptionsClass { | ||
required int32 i = 1; | ||
} | ||
|
||
enum OverriddenEnumName { | ||
FIRST = 0; | ||
OverriddenElementName = 1; | ||
} |
40 changes: 40 additions & 0 deletions
40
formats/protobuf/jvmTest/resources/NestedCollections.proto
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
syntax = "proto2"; | ||
|
||
package kotlinx.serialization.protobuf.schema.generator; | ||
|
||
// serial name 'kotlinx.serialization.protobuf.schema.GenerationTest.NestedCollections' | ||
message NestedCollections { | ||
repeated NestedCollections_intList intList = 1; | ||
repeated NestedCollections_messageList messageList = 2; | ||
repeated NestedCollections_mapInList mapInList = 3; | ||
map<string, NestedCollections_listInMap> listInMap = 4; | ||
} | ||
|
||
// This message was generated to support nested collection in list and does not present in Kotlin. | ||
// Containing message 'NestedCollections', field 'intList' | ||
message NestedCollections_intList { | ||
repeated int32 value = 1; | ||
} | ||
|
||
// This message was generated to support nested collection in list and does not present in Kotlin. | ||
// Containing message 'NestedCollections', field 'messageList' | ||
message NestedCollections_messageList { | ||
repeated OptionsClass value = 1; | ||
} | ||
|
||
// This message was generated to support nested collection in list and does not present in Kotlin. | ||
// Containing message 'NestedCollections', field 'mapInList' | ||
message NestedCollections_mapInList { | ||
map<string, OptionsClass> value = 1; | ||
} | ||
|
||
// This message was generated to support nested collection in map value and does not present in Kotlin. | ||
// Containing message 'NestedCollections', field 'listInMap' | ||
message NestedCollections_listInMap { | ||
repeated int32 value = 1; | ||
} | ||
|
||
// serial name 'kotlinx.serialization.protobuf.schema.GenerationTest.OptionsClass' | ||
message OptionsClass { | ||
required int32 i = 1; | ||
} |
46 changes: 46 additions & 0 deletions
46
formats/protobuf/jvmTest/resources/NullableNestedCollections.proto
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
syntax = "proto2"; | ||
|
||
package kotlinx.serialization.protobuf.schema.generator; | ||
|
||
// serial name 'kotlinx.serialization.protobuf.schema.GenerationTest.NullableNestedCollections' | ||
message NullableNestedCollections { | ||
repeated NullableNestedCollections_nullableIntList nullableIntList = 1; | ||
// WARNING: nullable map values can not be represented in protobuf | ||
map<string, NullableNestedCollections_nullableIntMap> nullableIntMap = 2; | ||
map<string, NullableNestedCollections_intMap> intMap = 3; | ||
repeated NullableNestedCollections_intList intList = 4; | ||
repeated NullableNestedCollections_legacyMap legacyMap = 5; | ||
} | ||
|
||
// This message was generated to support nested collection in list and does not present in Kotlin. | ||
// Containing message 'NullableNestedCollections', field 'nullableIntList' | ||
message NullableNestedCollections_nullableIntList { | ||
repeated int32 value = 1; | ||
} | ||
|
||
// This message was generated to support nested collection in map value and does not present in Kotlin. | ||
// Containing message 'NullableNestedCollections', field 'nullableIntMap' | ||
message NullableNestedCollections_nullableIntMap { | ||
repeated int32 value = 1; | ||
} | ||
|
||
// This message was generated to support nested collection in map value and does not present in Kotlin. | ||
// Containing message 'NullableNestedCollections', field 'intMap' | ||
message NullableNestedCollections_intMap { | ||
// WARNING: nullable elements of collections can not be represented in protobuf | ||
repeated int32 value = 1; | ||
} | ||
|
||
// This message was generated to support nested collection in list and does not present in Kotlin. | ||
// Containing message 'NullableNestedCollections', field 'intList' | ||
message NullableNestedCollections_intList { | ||
// WARNING: nullable elements of collections can not be represented in protobuf | ||
repeated int32 value = 1; | ||
} | ||
|
||
// This message was generated to support legacy map and does not present in Kotlin. | ||
// Containing message 'NullableNestedCollections', field 'legacyMap' | ||
message NullableNestedCollections_legacyMap { | ||
repeated int32 key = 1; | ||
repeated int32 value = 2; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
syntax = "proto2"; | ||
|
||
package kotlinx.serialization.protobuf.schema.generator; | ||
|
||
// serial name 'kotlinx.serialization.protobuf.schema.GenerationTest.OptionalClass' | ||
message OptionalClass { | ||
required int32 requiredInt = 1; | ||
// WARNING: a default value decoded when value is missing | ||
optional int32 optionalInt = 2; | ||
optional int32 nullableInt = 3; | ||
// WARNING: a default value decoded when value is missing | ||
optional int32 nullableOptionalInt = 4; | ||
} |
Oops, something went wrong.