Skip to content

Commit

Permalink
Fix `ClassCastException: class zio.schema.Schema$Lazy cannot be cast …
Browse files Browse the repository at this point in the history
…to class zio.schema.Schema$Record` (#3013)

* Add failing test

* Fix `ClassCastException`:

```scala
Exception in thread "zio-fiber-62,59,0" java.lang.NoClassDefFoundError: Could not initialize class my.company.app.main.MainApi$
    	at my.company.app.tests.utils$.$anonfun$2$$anonfun$2$$anonfun$1$$anonfun$1$$anonfun$2$$anonfun$2$$anonfun$2(utils.scala:46)
    	at zio.ZIO.map$$anonfun$1$$anonfun$1(ZIO.scala:973)
    	at zio.UnsafeVersionSpecific.implicitFunctionIsFunction$$anonfun$1(UnsafeVersionSpecific.scala:27)
    	at zio.Unsafe$.unsafe(Unsafe.scala:37)
    	at zio.ZIOCompanionVersionSpecific.succeed$$anonfun$1(ZIOCompanionVersionSpecific.scala:195)
    	at my.company.app.tests.utils.myLayer.serverLayer(utils.scala:46)
    	at my.company.app.tests.utils.myLayer.serverLayer(utils.scala:47)
    	at my.company.app.tests.apis.MySpec.spec(TestSourceApiIntegrationSpec.scala:62)
    	Suppressed: java.lang.ExceptionInInitializerError: Exception java.lang.ClassCastException: class zio.schema.Schema$Lazy cannot be cast to class zio.schema.Schema$Record (zio.schema.Schema$Lazy and zio.schema.Schema$Record are in unnamed module of loader sbt.internal.LayeredClassLoader @1c25c65d) [in thread "ZScheduler-Worker-7"]
    		at zio.http.endpoint.openapi.OpenAPIGen$.$anonfun$27(OpenAPIGen.scala:681)
    		at zio.Chunk.mapChunk(Chunk.scala:1055)
    		at zio.ChunkLike.map(ChunkLike.scala:121)
    		at zio.ChunkLike.map$(ChunkLike.scala:39)
    		at zio.Chunk.map(Chunk.scala:42)
    		at zio.http.endpoint.openapi.OpenAPIGen$.zio$http$endpoint$openapi$OpenAPIGen$$$_$genDiscriminator$1(OpenAPIGen.scala:685)
    		at zio.http.endpoint.openapi.OpenAPIGen$$anon$7.applyOrElse(OpenAPIGen.scala:735)
    		at zio.http.endpoint.openapi.OpenAPIGen$$anon$7.applyOrElse(OpenAPIGen.scala:727)
    		at zio.Chunk$Arr.collectChunk(Chunk.scala:1749)
    		at zio.Chunk.collectChunk(Chunk.scala:1036)
    		at zio.ChunkLike.collect(ChunkLike.scala:55)
    		at zio.ChunkLike.collect$(ChunkLike.scala:39)
    		at zio.Chunk.collect(Chunk.scala:42)
    		at zio.http.endpoint.openapi.OpenAPIGen$.componentSchemas$1(OpenAPIGen.scala:787)
    		at zio.http.endpoint.openapi.OpenAPIGen$.components$1(OpenAPIGen.scala:696)
    		at zio.http.endpoint.openapi.OpenAPIGen$.gen(OpenAPIGen.scala:802)
    		at zio.http.endpoint.openapi.OpenAPIGen$.fromEndpoints$$anonfun$3(OpenAPIGen.scala:485)
    		at scala.collection.immutable.List.map(List.scala:250)
    		at scala.collection.immutable.List.map(List.scala:79)
    		at zio.http.endpoint.openapi.OpenAPIGen$.fromEndpoints(OpenAPIGen.scala:485)
    		at zio.http.endpoint.openapi.OpenAPIGen$.fromEndpoints(OpenAPIGen.scala:491)
    		at my.company.app.api.Endpoints$.openAPI(Endpoints.scala:23)
    		at my.company.app.main.MainApi$.<clinit>(MainApi.scala:35)
    		at my.company.app.tests.utils$.$anonfun$2$$anonfun$2$$anonfun$1$$anonfun$1$$anonfun$2$$anonfun$1(utils.scala:44)
    		at zio.ZIO$.blocking$$anonfun$1(ZIO.scala:2877)
    		at zio.FiberRef$unsafe$$anon$2.getWith$$anonfun$1(FiberRef.scala:474)
```

* Fix tests
  • Loading branch information
guizmaii authored Aug 12, 2024
1 parent f79a945 commit 765c8bd
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -678,7 +678,10 @@ object OpenAPIGen {
// There should be no enums with cases that are not records with a nominal id
// TODO: not true. Since one could build a schema with a enum with a case that is a primitive
val typeId =
case_.schema
(case_.schema match {
case lzy: Schema.Lazy[_] => lzy.schema
case _ => case_.schema
})
.asInstanceOf[Schema.Record[_]]
.id
.asInstanceOf[TypeId.Nominal]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package zio.http.endpoint.openapi

import zio.test._

import zio.schema.{Schema, derived}

import zio.schema.DeriveSchema
import zio.test._
import zio.http.endpoint.Endpoint
import zio.http.codec.{Doc, HttpCodec}
import zio.http.endpoint.Endpoint
import zio.http.{MediaType, RoutePattern}
import zio.schema.annotation.{caseName, discriminatorName}
import zio.prelude.Subtype

object Scala3OpenAPIGenSpec extends ZIOSpecDefault {

type NonEmptyString = NonEmptyString.Type
object NonEmptyString extends Subtype[String] {
inline override def assertion = !zio.prelude.Assertion.isEmptyString

given zio.schema.Schema[Type] = derive
}

@discriminatorName("type")
sealed trait Input derives Schema
object Input {
@caseName("HTTP")
final case class HttpInput(request: HttpInput.Request) extends Input derives Schema

object HttpInput {
enum Method derives Schema {
case GET, POST, PUT
}

final case class Request(method: Method, url: String) derives Schema
}
}


sealed trait Error extends Product with Serializable
object Error {
final case class Error0(errors: List[String]) extends Error derives Schema
final case class Error1(message: String) extends Error derives Schema
}

@discriminatorName("type")
sealed trait Output derives Schema
object Output {
@caseName("HTTP")
final case class HttpOutput(body: Option[HttpOutput.Body], headers: Map[String, String]) extends Output derives Schema

object HttpOutput {
@discriminatorName("type")
sealed trait Body derives Schema
object Body {
@caseName("TEXT")
final case class Text(content: NonEmptyString) extends Body

@caseName("JSON")
final case class Json(content: NonEmptyString) extends Body

@caseName("XML")
final case class Xml(content: NonEmptyString) extends Body
}
}
}

private val testEndpoint =
(Endpoint(RoutePattern.POST / "test") ?? Doc.p("Test a Source"))
.outErrors[Error](
HttpCodec.error[Error.Error0](zio.http.Status.BadRequest),
HttpCodec.error[Error.Error1](zio.http.Status.InternalServerError),
)
.out[Output](MediaType.application.json)
.in[Input]

override val spec =
suite("OpenAPIGen")(
suite(".gen")(
test("doesn't throw 'ClassCastException: class zio.schema.Schema$Lazy cannot be cast to class zio.schema.Schema$Record'") {
zio.http.endpoint.openapi.OpenAPIGen.gen(endpoint = testEndpoint)
assertTrue(true)
},
)
)
}

0 comments on commit 765c8bd

Please sign in to comment.