Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error on Message.Builder subclass when running compileCommonMainKotlinMetadata This error should be fixed in the 4.8.1 build. #3294

Open
SureshKumarA24 opened this issue Feb 27, 2025 · 6 comments

Comments

@SureshKumarA24
Copy link

I'm trying to generate models for Android and iOS targets. The plugin generates (seemingly correct) code but there's an error on compileCommonMainKotlinMetadata task where it errors out with the error below:

`> Task :shared:compileCommonMainKotlinMetadata FAILED

e: file:///.../wiretest/shared/build/generated/source/wire/human/Person.kt:85:58 This class does not have a constructor

e: file:///.../wiretest/shared/build/generated/source/wire/human/Person.kt:230:65 This class does not have a constructor`

We need the fix in the particular version, because of the kotlin dependency

@oldergod
Copy link
Member

Can you share both the proto definition and the generated code that fails at compilation?

@SureshKumarA24
Copy link
Author

Compilation error

e: file:///.../wiretest/build/generated/source/wire/human/Person.kt:83:58 This class does not have a constructor
e: file:///.../wiretest/build/generated/source/wire/human/Person.kt:225:65 This class does not have a constructor

person.proto

syntax = "proto3";

package human;

message Person {
  string name = 1;
  PhoneNumber phone_number = 2;

  message PhoneNumber {
    string area = 1;
    string number = 2;
  }
}

Generated kotlin file

// Code generated by Wire protocol buffer compiler, do not edit.
// Source: human.Person in human/person.proto
package human

import com.squareup.wire.FieldEncoding
import com.squareup.wire.Message
import com.squareup.wire.ProtoAdapter
import com.squareup.wire.ProtoReader
import com.squareup.wire.ProtoWriter
import com.squareup.wire.ReverseProtoWriter
import com.squareup.wire.Syntax.PROTO_3
import com.squareup.wire.WireField
import com.squareup.wire.`internal`.JvmField
import com.squareup.wire.`internal`.sanitize
import kotlin.Any
import kotlin.Boolean
import kotlin.Int
import kotlin.Long
import kotlin.String
import okio.ByteString

public class Person internal constructor(
  @field:WireField(
    tag = 1,
    adapter = "com.squareup.wire.ProtoAdapter#STRING",
    label = WireField.Label.OMIT_IDENTITY,
    schemaIndex = 0,
  )
  @JvmField
  public val name: String = "",
  @field:WireField(
    tag = 2,
    adapter = "human.Person${'$'}PhoneNumber#ADAPTER",
    label = WireField.Label.OMIT_IDENTITY,
    jsonName = "phoneNumber",
    schemaIndex = 1,
  )
  @JvmField
  public val phone_number: PhoneNumber? = null,
  unknownFields: ByteString = ByteString.EMPTY,
) : Message<Person, Person.Builder>(ADAPTER, unknownFields) {
  override fun newBuilder(): Builder {
    val builder = Builder()
    builder.name = name
    builder.phone_number = phone_number
    builder.addUnknownFields(unknownFields)
    return builder
  }

  override fun equals(other: Any?): Boolean {
    if (other === this) return true
    if (other !is Person) return false
    if (unknownFields != other.unknownFields) return false
    if (name != other.name) return false
    if (phone_number != other.phone_number) return false
    return true
  }

  override fun hashCode(): Int {
    var result = super.hashCode
    if (result == 0) {
      result = unknownFields.hashCode()
      result = result * 37 + name.hashCode()
      result = result * 37 + (phone_number?.hashCode() ?: 0)
      super.hashCode = result
    }
    return result
  }

  override fun toString(): String {
    val result = mutableListOf<String>()
    result += """name=${sanitize(name)}"""
    if (phone_number != null) result += """phone_number=$phone_number"""
    return result.joinToString(prefix = "Person{", separator = ", ", postfix = "}")
  }

  public fun copy(
    name: String = this.name,
    phone_number: PhoneNumber? = this.phone_number,
    unknownFields: ByteString = this.unknownFields,
  ): Person = Person(name, phone_number, unknownFields)

  public class Builder : Message.Builder<Person, Builder>() {
    @JvmField
    public var name: String = ""

    @JvmField
    public var phone_number: PhoneNumber? = null

    public fun name(name: String): Builder {
      this.name = name
      return this
    }

    public fun phone_number(phone_number: PhoneNumber?): Builder {
      this.phone_number = phone_number
      return this
    }

    override fun build(): Person = Person(
      name = name,
      phone_number = phone_number,
      unknownFields = buildUnknownFields()
    )
  }

  public companion object {
    @JvmField
    public val ADAPTER: ProtoAdapter<Person> = object : ProtoAdapter<Person>(
      FieldEncoding.LENGTH_DELIMITED, 
      Person::class, 
      "type.googleapis.com/human.Person", 
      PROTO_3, 
      null, 
      "human/person.proto"
    ) {
      override fun encodedSize(`value`: Person): Int {
        var size = value.unknownFields.size
        if (value.name != "") size += ProtoAdapter.STRING.encodedSizeWithTag(1, value.name)
        if (value.phone_number != null) size += PhoneNumber.ADAPTER.encodedSizeWithTag(2,
            value.phone_number)
        return size
      }

      override fun encode(writer: ProtoWriter, `value`: Person) {
        if (value.name != "") ProtoAdapter.STRING.encodeWithTag(writer, 1, value.name)
        if (value.phone_number != null) PhoneNumber.ADAPTER.encodeWithTag(writer, 2,
            value.phone_number)
        writer.writeBytes(value.unknownFields)
      }

      override fun encode(writer: ReverseProtoWriter, `value`: Person) {
        writer.writeBytes(value.unknownFields)
        if (value.phone_number != null) PhoneNumber.ADAPTER.encodeWithTag(writer, 2,
            value.phone_number)
        if (value.name != "") ProtoAdapter.STRING.encodeWithTag(writer, 1, value.name)
      }

      override fun decode(reader: ProtoReader): Person {
        var name: String = ""
        var phone_number: PhoneNumber? = null
        val unknownFields = reader.forEachTag { tag ->
          when (tag) {
            1 -> name = ProtoAdapter.STRING.decode(reader)
            2 -> phone_number = PhoneNumber.ADAPTER.decode(reader)
            else -> reader.readUnknownField(tag)
          }
        }
        return Person(
          name = name,
          phone_number = phone_number,
          unknownFields = unknownFields
        )
      }

      override fun redact(`value`: Person): Person = value.copy(
        phone_number = value.phone_number?.let(PhoneNumber.ADAPTER::redact),
        unknownFields = ByteString.EMPTY
      )
    }

    private const val serialVersionUID: Long = 0L
  }

  public class PhoneNumber internal constructor(
    @field:WireField(
      tag = 1,
      adapter = "com.squareup.wire.ProtoAdapter#STRING",
      label = WireField.Label.OMIT_IDENTITY,
      schemaIndex = 0,
    )
    @JvmField
    public val area: String = "",
    @field:WireField(
      tag = 2,
      adapter = "com.squareup.wire.ProtoAdapter#STRING",
      label = WireField.Label.OMIT_IDENTITY,
      schemaIndex = 1,
    )
    @JvmField
    public val number: String = "",
    unknownFields: ByteString = ByteString.EMPTY,
  ) : Message<PhoneNumber, PhoneNumber.Builder>(ADAPTER, unknownFields) {
    override fun newBuilder(): Builder {
      val builder = Builder()
      builder.area = area
      builder.number = number
      builder.addUnknownFields(unknownFields)
      return builder
    }

    override fun equals(other: Any?): Boolean {
      if (other === this) return true
      if (other !is PhoneNumber) return false
      if (unknownFields != other.unknownFields) return false
      if (area != other.area) return false
      if (number != other.number) return false
      return true
    }

    override fun hashCode(): Int {
      var result = super.hashCode
      if (result == 0) {
        result = unknownFields.hashCode()
        result = result * 37 + area.hashCode()
        result = result * 37 + number.hashCode()
        super.hashCode = result
      }
      return result
    }

    override fun toString(): String {
      val result = mutableListOf<String>()
      result += """area=${sanitize(area)}"""
      result += """number=${sanitize(number)}"""
      return result.joinToString(prefix = "PhoneNumber{", separator = ", ", postfix = "}")
    }

    public fun copy(
      area: String = this.area,
      number: String = this.number,
      unknownFields: ByteString = this.unknownFields,
    ): PhoneNumber = PhoneNumber(area, number, unknownFields)

    public class Builder : Message.Builder<PhoneNumber, Builder>() {
      @JvmField
      public var area: String = ""

      @JvmField
      public var number: String = ""

      public fun area(area: String): Builder {
        this.area = area
        return this
      }

      public fun number(number: String): Builder {
        this.number = number
        return this
      }

      override fun build(): PhoneNumber = PhoneNumber(
        area = area,
        number = number,
        unknownFields = buildUnknownFields()
      )
    }

    public companion object {
      @JvmField
      public val ADAPTER: ProtoAdapter<PhoneNumber> = object : ProtoAdapter<PhoneNumber>(
        FieldEncoding.LENGTH_DELIMITED, 
        PhoneNumber::class, 
        "type.googleapis.com/human.Person.PhoneNumber", 
        PROTO_3, 
        null, 
        "human/person.proto"
      ) {
        override fun encodedSize(`value`: PhoneNumber): Int {
          var size = value.unknownFields.size
          if (value.area != "") size += ProtoAdapter.STRING.encodedSizeWithTag(1, value.area)
          if (value.number != "") size += ProtoAdapter.STRING.encodedSizeWithTag(2, value.number)
          return size
        }

        override fun encode(writer: ProtoWriter, `value`: PhoneNumber) {
          if (value.area != "") ProtoAdapter.STRING.encodeWithTag(writer, 1, value.area)
          if (value.number != "") ProtoAdapter.STRING.encodeWithTag(writer, 2, value.number)
          writer.writeBytes(value.unknownFields)
        }

        override fun encode(writer: ReverseProtoWriter, `value`: PhoneNumber) {
          writer.writeBytes(value.unknownFields)
          if (value.number != "") ProtoAdapter.STRING.encodeWithTag(writer, 2, value.number)
          if (value.area != "") ProtoAdapter.STRING.encodeWithTag(writer, 1, value.area)
        }

        override fun decode(reader: ProtoReader): PhoneNumber {
          var area: String = ""
          var number: String = ""
          val unknownFields = reader.forEachTag { tag ->
            when (tag) {
              1 -> area = ProtoAdapter.STRING.decode(reader)
              2 -> number = ProtoAdapter.STRING.decode(reader)
              else -> reader.readUnknownField(tag)
            }
          }
          return PhoneNumber(
            area = area,
            number = number,
            unknownFields = unknownFields
          )
        }

        override fun redact(`value`: PhoneNumber): PhoneNumber = value.copy(
          unknownFields = ByteString.EMPTY
        )
      }

      private const val serialVersionUID: Long = 0L
    }
  }
}

@SureshKumarA24
Copy link
Author

We found a similar issue in the issue list and noticed that you fixed it in version 5.3.0. However, since we haven’t upgraded to Kotlin 2.0 yet, so we need this fix in the 4.8.1 build.

Please check: #2707

@oldergod
Copy link
Member

If #2707 has your fix, you could use 4.9.11

@SureshKumarA24
Copy link
Author

If #2707 has your fix, you could use 4.9.11

We cannot use this version because we are unable to upgrade to Kotlin 1.8.20.

@oldergod
Copy link
Member

Unfortunately we might only add bug fixes to 4.9.x or later versions. Hopefully you'll be able to upgrade to more recent versions of Kotlin and bump Wire as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants