guardrail
guardrail copied to clipboard
schema and scala type names conflicts
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
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).
Sure, i can fix it.