guardrail icon indicating copy to clipboard operation
guardrail copied to clipboard

schema and scala type names conflicts

Open justcoon opened this issue 3 years ago • 2 comments

Hi,

i have following schema

   Product:
      type: object
      properties:
        id:
          type: string
        type:
          $ref: '#/components/schemas/Type'
      required:
        - shape
        - id
    Type:
      type: string
      enum:
        - Service
        - Digital

which generate following code

package com.product.api

import cats.syntax.either._
import io.circe._
import io.circe.syntax._
import cats.implicits._
import _root_.com.upstartcommerce.catalog2.api.openapi.Implicits._
case class Product(id: String, `type`: Option[Type] = None)
object Product {
  implicit val encodeProduct: Encoder.AsObject[Product] = {
    val readOnlyKeys = Set[String]()
    Encoder.AsObject.instance[Product](a => JsonObject.fromIterable(Vector(("id", a.id.asJson), ("type", a.`type`.asJson)))).mapJsonObject(_.filterKeys(key => !(readOnlyKeys contains key)))
  }
  implicit val decodeProduct: Decoder[Product] = new Decoder[Product] { final def apply(c: HCursor): Decoder.Result[Product] = for (v0 <- c.downField("id").as[String]; v1 <- c.downField("type").as[Option[Type]]) yield Product(v0, v1) }
}

sealed abstract class Type(val value: String) extends Product with Serializable { override def toString: String = value.toString }
object Type {
  object members {
    case object Service extends Type("Service")
    case object Digital extends Type("Digital")
  }
  val Service: Type = members.Service
  val Digital: Type = members.Digital
  val values = Vector(Service, Digital)
  implicit val encodeType: Encoder[Type] = Encoder[String].contramap(_.value)
  implicit val decodeType: Decoder[Type] = Decoder[String].emap(value => from(value).toRight(s"$value not a member of Type"))
  implicit val showType: Show[Type] = Show[String].contramap[Type](_.value)
  def from(value: String): Option[Type] = values.find(_.value == value)
  implicit val order: cats.Order[Type] = cats.Order.by[Type, Int](values.indexOf)
}

however there is a problem there, as com.product.api.Product, overrides scala.Product of

sealed abstract class Type(val value: String) extends Product

i think that generated code should have full class names, to avoid those types of conflicts.

sealed abstract class Type(val value: String) extends _root_.scala.Product

and probably not just for Product, also for io.circe.Encoder ..., to avoid conflicts with names in defined schema

what do you think about that?

thank you for your response

Peter

justcoon avatar Jun 23 '21 17:06 justcoon

Yep, definitely. We've been slowly fixing this up in places over time, but, as you've noticed there are still some that aren't handled. Would you be open to diving in and helping to make this change? This one in particular shouldn't be too hard to do (I believe CirceProtocolGenerator.scala is the right place).

kelnos avatar Jun 23 '21 18:06 kelnos

Sure, i can fix it.

justcoon avatar Jun 23 '21 19:06 justcoon