Skip to content

[Feature Request] Kotlin codegen improvements for naming, constructors, and optional field access #3483

@chuanwise

Description

@chuanwise

Hi Wire team 👋,

First of all, thanks for Wire — it’s a fantastic tool and we’re happily using it in production with Kotlin and gRPC. I really like the wire function that compiling the optional fields to nullable properties.

While integrating Wire into a multi-language environment, we ran into a few Kotlin codegen limitations that I believe could be valuable feature additions. I’d like to propose the following enhancements:


1. Automatic field name conversion to lowerCamelCase in Kotlin

Problem

Our .proto files are shared across multiple languages (Go, Python, JS, Kotlin, etc.), so we use snake_case field names in proto files for consistency.

Example:

message FeatureReq {
  string feature_name = 1;
  int64 created_at = 2;
}

Currently, Wire generates Kotlin properties exactly as-is:

val feature_name: String
val created_at: Long

However, idiomatic Kotlin strongly prefers lowerCamelCase:

val featureName: String
val createdAt: Long

Request

Provide an option in Kotlin codegen to automatically convert proto field names to lowerCamelCase, while still mapping correctly to the original proto names.

Possible approaches: A codegen flag (e.g. kotlin { camelCaseFields = true }). Or default behavior aligned with Kotlin conventions (similar to how some JSON serializers behave)

2. Additional constructor with required (non-optional) fields only

Problem

Wire-generated Kotlin message classes typically expose a single constructor where all fields (including optional ones) are nullable or defaulted.

For example:

FeatureReq(
  featureName = featureName,
  createdAt = createdAt,
  description = null
)

This makes it easy to accidentally construct invalid domain objects and weakens compile-time guarantees.

Request

If there are some optional fields, generate an additional constructor where:

  • Non-optional fields are required parameters

  • Optional fields are omitted or defaulted

Example:

// existing constructor
FeatureReq(
  featureName: String = "",
  createdAt: Long = 0L,
  description: String? = null
)

// new constructor
constructor(
  featureName: String,
  createdAt: Long,
  description: String? = null
)

This would significantly improve Kotlin ergonomics and domain safety.

3. fieldOrFail accessors for optional fields

Problem

Optional fields are nullable in Kotlin, which is correct at the model level, but in some layers (e.g. application logic) a missing value should be treated as a programmer error.

Currently, users must manually write:

val value = featureReq.description
  ?: error("description is required")

Request

For optional fields, generate an additional accessor:

val descriptionOrFail: String

Which throws a clear exception if the field is null.

This pattern is very common in Kotlin codebases and would greatly reduce boilerplate while making intent explicit.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions