Skip to content

Commit 6118696

Browse files
authored
generate json converter functions for krotoDC dataclasses (#25)
* generate json converter functions for krotoDC dataclasses * add `protobuf-java-util` dependency to README
1 parent 20d147f commit 6118696

File tree

7 files changed

+146
-0
lines changed

7 files changed

+146
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ In your project's `build.gradle.kts` file, add the following dependencies:
1919
```kotlin
2020
dependencies {
2121
implementation("com.google.protobuf:protobuf-java:3.25.3")
22+
implementation("com.google.protobuf:protobuf-java-util:3.25.3")
2223
implementation("io.grpc:grpc-stub:1.61.1")
2324
implementation("io.grpc:grpc-kotlin-stub:1.4.1")
2425
implementation("io.github.mscheong01:krotoDC-core:1.0.7")

generator/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ dependencies {
1717
// implementation("io.grpc:grpc-protobuf:${rootProject.ext["grpcJavaVersion"]}")
1818
// https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java
1919
implementation("com.google.protobuf:protobuf-java:${rootProject.ext["protobufVersion"]}")
20+
implementation("com.google.protobuf:protobuf-java-util:${rootProject.ext["protobufVersion"]}")
2021

2122
implementation(kotlin("reflect"))
2223
implementation("com.squareup:kotlinpoet:${rootProject.ext["kotlinPoetVersion"]}")

generator/src/main/kotlin/io/github/mscheong01/krotodc/specgenerators/file/ConverterGenerator.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ import com.squareup.kotlinpoet.FunSpec
1919
import io.github.mscheong01.krotodc.import.FunSpecsWithImports
2020
import io.github.mscheong01.krotodc.import.Import
2121
import io.github.mscheong01.krotodc.specgenerators.FileSpecGenerator
22+
import io.github.mscheong01.krotodc.specgenerators.function.FromJsonFunctionGenerator
2223
import io.github.mscheong01.krotodc.specgenerators.function.MessageToDataClassFunctionGenerator
2324
import io.github.mscheong01.krotodc.specgenerators.function.MessageToProtoFunctionGenerator
25+
import io.github.mscheong01.krotodc.specgenerators.function.ToJsonFunctionGenerator
2426
import io.github.mscheong01.krotodc.util.addAllImports
2527
import io.github.mscheong01.krotodc.util.isPredefinedType
2628
import io.github.mscheong01.krotodc.util.krotoDCPackage
@@ -29,6 +31,8 @@ class ConverterGenerator : FileSpecGenerator {
2931

3032
val messageToDataClassGenerator = MessageToDataClassFunctionGenerator()
3133
val messageToProtoGenerator = MessageToProtoFunctionGenerator()
34+
val toJsonFunctionGenerator = ToJsonFunctionGenerator()
35+
val fromJsonFunctionGenerator = FromJsonFunctionGenerator()
3236

3337
override fun generate(fileDescriptor: Descriptors.FileDescriptor): List<FileSpec> {
3438
val fileSpecs = mutableMapOf<String, FileSpec>()
@@ -64,6 +68,15 @@ class ConverterGenerator : FileSpecGenerator {
6468
funSpecs.addAll(it.funSpecs)
6569
imports.addAll(it.imports)
6670
}
71+
toJsonFunctionGenerator.generate(messageDescriptor).let {
72+
funSpecs.addAll(it.funSpecs)
73+
imports.addAll(it.imports)
74+
}
75+
fromJsonFunctionGenerator.generate(messageDescriptor).let {
76+
funSpecs.addAll(it.funSpecs)
77+
imports.addAll(it.imports)
78+
}
79+
6780
messageDescriptor.nestedTypes.forEach { nestedType ->
6881
generateConvertersForMessageDescriptor(nestedType).let {
6982
funSpecs.addAll(it.funSpecs)

generator/src/main/kotlin/io/github/mscheong01/krotodc/specgenerators/file/DataClassGenerator.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@ class DataClassGenerator : FileSpecGenerator {
205205
.addMember("forProto = %L::class", messageDescriptor.protobufJavaTypeName)
206206
.build()
207207
)
208+
209+
dataClassBuilder.addType(TypeSpec.companionObjectBuilder().build())
208210
return TypeSpecsWithImports(
209211
listOf(dataClassBuilder.build()),
210212
imports
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright 2024 Minsoo Cheong
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
package io.github.mscheong01.krotodc.specgenerators.function
15+
16+
import com.google.protobuf.Descriptors.Descriptor
17+
import com.squareup.kotlinpoet.ClassName
18+
import com.squareup.kotlinpoet.FunSpec
19+
import com.squareup.kotlinpoet.ParameterSpec
20+
import io.github.mscheong01.krotodc.import.FunSpecsWithImports
21+
import io.github.mscheong01.krotodc.import.Import
22+
import io.github.mscheong01.krotodc.specgenerators.FunSpecGenerator
23+
import io.github.mscheong01.krotodc.util.krotoDCTypeName
24+
import io.github.mscheong01.krotodc.util.protobufJavaTypeName
25+
26+
class FromJsonFunctionGenerator : FunSpecGenerator<Descriptor> {
27+
override fun generate(descriptor: Descriptor): FunSpecsWithImports {
28+
val imports = mutableSetOf<Import>()
29+
val generatedType = descriptor.krotoDCTypeName
30+
val generatedTypeCompanion = ClassName(
31+
generatedType.packageName,
32+
*generatedType.simpleNames.toTypedArray(),
33+
"Companion"
34+
)
35+
val protoType = descriptor.protobufJavaTypeName
36+
val functionBuilder = FunSpec.builder("fromJson")
37+
.addParameter(
38+
ParameterSpec.builder(
39+
"json",
40+
String::class
41+
).build()
42+
)
43+
.receiver(generatedTypeCompanion)
44+
.returns(generatedType)
45+
functionBuilder.addCode("return %L.newBuilder().apply { JsonFormat.parser().ignoringUnknownFields().merge(json, this@apply) }.build().toDataClass();\n", protoType)
46+
47+
imports.add(Import("com.google.protobuf.util", listOf("JsonFormat")))
48+
return FunSpecsWithImports(
49+
listOf(functionBuilder.build()),
50+
imports
51+
)
52+
}
53+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Copyright 2024 Minsoo Cheong
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
package io.github.mscheong01.krotodc.specgenerators.function
15+
16+
import com.google.protobuf.Descriptors.Descriptor
17+
import com.squareup.kotlinpoet.FunSpec
18+
import io.github.mscheong01.krotodc.import.FunSpecsWithImports
19+
import io.github.mscheong01.krotodc.import.Import
20+
import io.github.mscheong01.krotodc.specgenerators.FunSpecGenerator
21+
import io.github.mscheong01.krotodc.util.krotoDCTypeName
22+
23+
class ToJsonFunctionGenerator : FunSpecGenerator<Descriptor> {
24+
override fun generate(descriptor: Descriptor): FunSpecsWithImports {
25+
val imports = mutableSetOf<Import>()
26+
val generatedType = descriptor.krotoDCTypeName
27+
val functionBuilder = FunSpec.builder("toJson")
28+
.receiver(generatedType)
29+
.returns(String::class)
30+
functionBuilder.addCode("return JsonFormat.printer().print(this@toJson.toProto())")
31+
imports.add(Import("com.google.protobuf.util", listOf("JsonFormat")))
32+
return FunSpecsWithImports(
33+
listOf(functionBuilder.build()),
34+
imports
35+
)
36+
}
37+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright 2024 Minsoo Cheong
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
package io.github.mscheong01.krotodc
15+
16+
import io.github.mscheong01.test.Person
17+
import io.github.mscheong01.test.krotodc.person.fromJson
18+
import io.github.mscheong01.test.krotodc.person.toDataClass
19+
import io.github.mscheong01.test.krotodc.person.toJson
20+
import org.assertj.core.api.Assertions
21+
import org.junit.jupiter.api.Test
22+
23+
class JsonConverterTest {
24+
25+
@Test
26+
fun `test simple message`() {
27+
val proto = Person.newBuilder()
28+
.setName("John")
29+
.setAge(30)
30+
.build()
31+
val dataClass = proto.toDataClass()
32+
val json = dataClass.toJson()
33+
Assertions.assertThat(json).isEqualTo(
34+
"{\n \"name\": \"John\",\n \"age\": 30\n}"
35+
)
36+
val deserializedDataClass = io.github.mscheong01.test.krotodc.Person.fromJson(json)
37+
Assertions.assertThat(dataClass).isEqualTo(deserializedDataClass)
38+
}
39+
}

0 commit comments

Comments
 (0)