📜
Kompendium
  • Introduction
  • Plugins
    • Notarized Application
    • Notarized Route
    • Notarized Resources
  • Concepts
    • Enrichment
  • Helpers
    • Protobuf java converter
  • The Playground
Powered by GitBook
On this page
  1. Helpers

Protobuf java converter

The Protobuf java converter functions allow you to generate documentation from your generated Java classes. Since Kompendium relies a lot on KProperties we have yet to find a way to connect this with our Java. For now the documentation is generated for the customTypes in NotarizedApplication.

Usage with Kotlinx

setup:

 install(ContentNegotiation) {
  json(Json {
    encodeDefaults = false
    // Combine the kompendium serializers with your custom java proto serializers 
    serializersModule =
      KompendiumSerializersModule.module + SerializersModule { serializersModule = yourCustomProtoSerializers }
  })
}

For one message and all its nested sub messages:

private fun Application.mainModule() {
  // ...
  install(NotarizedApplication()) {
    spec = baseSpec
    customTypes = MyJavaProto.getDefaultInstance().createCustomTypesForTypeAndSubTypes().toMap()
  }
}

For multiple messages and their submesages:

private fun Application.mainModule() {
  // ...
  install(NotarizedApplication()) {
    spec = baseSpec
    customTypes = MyJavaProto.getDefaultInstance().createCustomTypesForTypeAndSubTypes()
      .plus(AnotherJavaProto.getDefaultInstance().createCustomTypesForTypeAndSubTypes()).toMap()
  }
}

Example User

The protobuf that is used on our endpoint

message User {
  string id = 1;
  string email = 2;
  string mobile_phone = 3;
  string name = 4;
}

A custom serializer deserializer:

@OptIn(ExperimentalSerializationApi::class)
object UserSerializer : KSerializer<User> {

  override val descriptor: SerialDescriptor = buildClassSerialDescriptor("User") {
    element("id", serialDescriptor<String>())
    element("email", serialDescriptor<String>())
    element("mobile_phone", serialDescriptor<String>())
    element("name", serialDescriptor<String>())
  }

  override fun deserialize(decoder: Decoder): User {
    return decoder.decodeStructure(descriptor) {
      var id: String? = null
      var email: String? = null
      var mobilePhone: String? = null
      var name: String? = null

      loop@ while (true) {
        when (val index = decodeElementIndex(descriptor)) {
          CompositeDecoder.DECODE_DONE -> break@loop
          0 -> id = decodeStringElement(descriptor, index)
          1 -> email = decodeStringElement(descriptor, index)
          2 -> mobilePhone = decodeStringElement(descriptor, index)
          3 -> name = decodeStringElement(descriptor, index)
          else -> throw   RuntimeException(
            "Unexpected index field ${descriptor.getElementName(index)}"
          )
        }
      }
      // building the protobuf object
      val user = User.newBuilder().apply {
        id?.let { v -> this.id = v }
        email?.let { v -> this.email = v }
        mobilePhone?.let { v -> this.mobilePhone = v }
        name?.let { v -> this.name = v }
      }.build()
      user
    }
  }

  override fun serialize(encoder: Encoder, value: User) {
    encoder.encodeStructure(descriptor) {
      encodeStringElement(descriptor, 0, value.id)
      encodeStringElement(descriptor, 1, value.email)
      encodeStringElement(descriptor, 2, value.mobilePhone)
      encodeStringElement(descriptor, 3, value.name)
    }
  }
}

Setting the content type:

install(ContentNegotiation) {
  json(Json {
    encodeDefaults = false
    // Combine the kompendium serializers with your custom java proto serializers 
    serializersModule =
      KompendiumSerializersModule.module + SerializersModule { 
        serializersModule = SerializersModule {
          contextual(UserSerializer)
        }
      }
  })
}

The installation of the noterized application:

install(NotarizedApplication()) {
  spec = baseSpec
  customTypes = User.getDefaultInstance().createCustomTypesForTypeAndSubTypes().toMap()
}

Route configuration as you normally would with one exception which is createType() to create kotlin type from a javaClass.

private fun Route.userDocumentation() {
  install(NotarizedRoute()) {
    post = PostInfo.builder {
      summary("My User API")
      description("Create a user")
      request {
        requestType(User::class.createType())
        description("My user creation object")
      }
      response {
        responseCode(HttpStatusCode.OK)
        responseType(CreateUserResponse::class.createType())
        description("Returns simulation object")
      }
      canRespond {
        responseCode(HttpStatusCode.NotFound)
        responseType<String>()
        description("Indicates that the user could not be found")
      }
    }
  }
}
PreviousHelpersNextThe Playground

Last updated 2 years ago