Skip to content

Commit

Permalink
generate json converter functions for krotoDC dataclasses (#25)
Browse files Browse the repository at this point in the history
* generate json converter functions for krotoDC dataclasses

* add `protobuf-java-util` dependency to README
  • Loading branch information
mscheong01 committed Mar 1, 2024
1 parent 20d147f commit 6118696
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ In your project's `build.gradle.kts` file, add the following dependencies:
```kotlin
dependencies {
implementation("com.google.protobuf:protobuf-java:3.25.3")
implementation("com.google.protobuf:protobuf-java-util:3.25.3")
implementation("io.grpc:grpc-stub:1.61.1")
implementation("io.grpc:grpc-kotlin-stub:1.4.1")
implementation("io.github.mscheong01:krotoDC-core:1.0.7")
Expand Down
1 change: 1 addition & 0 deletions generator/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ dependencies {
// implementation("io.grpc:grpc-protobuf:${rootProject.ext["grpcJavaVersion"]}")
// https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java
implementation("com.google.protobuf:protobuf-java:${rootProject.ext["protobufVersion"]}")
implementation("com.google.protobuf:protobuf-java-util:${rootProject.ext["protobufVersion"]}")

implementation(kotlin("reflect"))
implementation("com.squareup:kotlinpoet:${rootProject.ext["kotlinPoetVersion"]}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ import com.squareup.kotlinpoet.FunSpec
import io.github.mscheong01.krotodc.import.FunSpecsWithImports
import io.github.mscheong01.krotodc.import.Import
import io.github.mscheong01.krotodc.specgenerators.FileSpecGenerator
import io.github.mscheong01.krotodc.specgenerators.function.FromJsonFunctionGenerator
import io.github.mscheong01.krotodc.specgenerators.function.MessageToDataClassFunctionGenerator
import io.github.mscheong01.krotodc.specgenerators.function.MessageToProtoFunctionGenerator
import io.github.mscheong01.krotodc.specgenerators.function.ToJsonFunctionGenerator
import io.github.mscheong01.krotodc.util.addAllImports
import io.github.mscheong01.krotodc.util.isPredefinedType
import io.github.mscheong01.krotodc.util.krotoDCPackage
Expand All @@ -29,6 +31,8 @@ class ConverterGenerator : FileSpecGenerator {

val messageToDataClassGenerator = MessageToDataClassFunctionGenerator()
val messageToProtoGenerator = MessageToProtoFunctionGenerator()
val toJsonFunctionGenerator = ToJsonFunctionGenerator()
val fromJsonFunctionGenerator = FromJsonFunctionGenerator()

override fun generate(fileDescriptor: Descriptors.FileDescriptor): List<FileSpec> {
val fileSpecs = mutableMapOf<String, FileSpec>()
Expand Down Expand Up @@ -64,6 +68,15 @@ class ConverterGenerator : FileSpecGenerator {
funSpecs.addAll(it.funSpecs)
imports.addAll(it.imports)
}
toJsonFunctionGenerator.generate(messageDescriptor).let {
funSpecs.addAll(it.funSpecs)
imports.addAll(it.imports)
}
fromJsonFunctionGenerator.generate(messageDescriptor).let {
funSpecs.addAll(it.funSpecs)
imports.addAll(it.imports)
}

messageDescriptor.nestedTypes.forEach { nestedType ->
generateConvertersForMessageDescriptor(nestedType).let {
funSpecs.addAll(it.funSpecs)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ class DataClassGenerator : FileSpecGenerator {
.addMember("forProto = %L::class", messageDescriptor.protobufJavaTypeName)
.build()
)

dataClassBuilder.addType(TypeSpec.companionObjectBuilder().build())
return TypeSpecsWithImports(
listOf(dataClassBuilder.build()),
imports
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright 2024 Minsoo Cheong
//
// 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 io.github.mscheong01.krotodc.specgenerators.function

import com.google.protobuf.Descriptors.Descriptor
import com.squareup.kotlinpoet.ClassName
import com.squareup.kotlinpoet.FunSpec
import com.squareup.kotlinpoet.ParameterSpec
import io.github.mscheong01.krotodc.import.FunSpecsWithImports
import io.github.mscheong01.krotodc.import.Import
import io.github.mscheong01.krotodc.specgenerators.FunSpecGenerator
import io.github.mscheong01.krotodc.util.krotoDCTypeName
import io.github.mscheong01.krotodc.util.protobufJavaTypeName

class FromJsonFunctionGenerator : FunSpecGenerator<Descriptor> {
override fun generate(descriptor: Descriptor): FunSpecsWithImports {
val imports = mutableSetOf<Import>()
val generatedType = descriptor.krotoDCTypeName
val generatedTypeCompanion = ClassName(
generatedType.packageName,
*generatedType.simpleNames.toTypedArray(),
"Companion"
)
val protoType = descriptor.protobufJavaTypeName
val functionBuilder = FunSpec.builder("fromJson")
.addParameter(
ParameterSpec.builder(
"json",
String::class
).build()
)
.receiver(generatedTypeCompanion)
.returns(generatedType)
functionBuilder.addCode("return %L.newBuilder().apply { JsonFormat.parser().ignoringUnknownFields().merge(json, this@apply) }.build().toDataClass();\n", protoType)

imports.add(Import("com.google.protobuf.util", listOf("JsonFormat")))
return FunSpecsWithImports(
listOf(functionBuilder.build()),
imports
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright 2024 Minsoo Cheong
//
// 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 io.github.mscheong01.krotodc.specgenerators.function

import com.google.protobuf.Descriptors.Descriptor
import com.squareup.kotlinpoet.FunSpec
import io.github.mscheong01.krotodc.import.FunSpecsWithImports
import io.github.mscheong01.krotodc.import.Import
import io.github.mscheong01.krotodc.specgenerators.FunSpecGenerator
import io.github.mscheong01.krotodc.util.krotoDCTypeName

class ToJsonFunctionGenerator : FunSpecGenerator<Descriptor> {
override fun generate(descriptor: Descriptor): FunSpecsWithImports {
val imports = mutableSetOf<Import>()
val generatedType = descriptor.krotoDCTypeName
val functionBuilder = FunSpec.builder("toJson")
.receiver(generatedType)
.returns(String::class)
functionBuilder.addCode("return JsonFormat.printer().print([email protected]())")
imports.add(Import("com.google.protobuf.util", listOf("JsonFormat")))
return FunSpecsWithImports(
listOf(functionBuilder.build()),
imports
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2024 Minsoo Cheong
//
// 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 io.github.mscheong01.krotodc

import io.github.mscheong01.test.Person
import io.github.mscheong01.test.krotodc.person.fromJson
import io.github.mscheong01.test.krotodc.person.toDataClass
import io.github.mscheong01.test.krotodc.person.toJson
import org.assertj.core.api.Assertions
import org.junit.jupiter.api.Test

class JsonConverterTest {

@Test
fun `test simple message`() {
val proto = Person.newBuilder()
.setName("John")
.setAge(30)
.build()
val dataClass = proto.toDataClass()
val json = dataClass.toJson()
Assertions.assertThat(json).isEqualTo(
"{\n \"name\": \"John\",\n \"age\": 30\n}"
)
val deserializedDataClass = io.github.mscheong01.test.krotodc.Person.fromJson(json)
Assertions.assertThat(dataClass).isEqualTo(deserializedDataClass)
}
}

0 comments on commit 6118696

Please sign in to comment.