Skip to content

[BUG] Scala 2.13 OpenApi generated code causes a StackOverflow (Scala3 generated code does not) #4911

@dwalend

Description

@dwalend

Tapir version: 1.11.50

Scala version: 2.13.16 (it works on the Scala 3.3.6 side of the cross project build).

Tapir generates this line of code from NiFi's OpenApi spec for Scala 2.13:

  implicit lazy val controllerServiceReferencingComponentDTOTapirSchema: sttp.tapir.Schema[ControllerServiceReferencingComponentDTO] = sttp.tapir.Schema.derived
  implicit lazy val controllerServiceReferencingComponentEntityTapirSchema: sttp.tapir.Schema[ControllerServiceReferencingComponentEntity] = sttp.tapir.Schema.derived

This causes an infinite recursion at class load time:

An exception or error caused a run to abort. 
java.lang.StackOverflowError
	at com.macrohealth.platform.api.nififromopenapi.NifiFromOpenApiSchemas2$.controllerServiceReferencingComponentDTOTapirSchema$lzycompute(NifiFromOpenApiSchemas2.scala:119)
	at com.macrohealth.platform.api.nififromopenapi.NifiFromOpenApiSchemas2$.controllerServiceReferencingComponentDTOTapirSchema(NifiFromOpenApiSchemas2.scala:119)
	at com.macrohealth.platform.api.nififromopenapi.NifiFromOpenApiSchemas2$.controllerServiceReferencingComponentEntityTapirSchema$lzycompute(NifiFromOpenApiSchemas2.scala:120)
	at com.macrohealth.platform.api.nififromopenapi.NifiFromOpenApiSchemas2$.controllerServiceReferencingComponentEntityTapirSchema(NifiFromOpenApiSchemas2.scala:120)

I was able to isolate the problem in a test:

  "Schemas that reference each other" should "not have a circular dependency" in {
    // The lazy val evaluation hits the circular dependency, but defs won't
    val schema1 = NifiFromOpenApiSchemas2.controllerServiceReferencingComponentDTOTapirSchema
    val schema2 = NifiFromOpenApiSchemas2.controllerServiceReferencingComponentEntityTapirSchema

    assert(schema1 != schema2) //if the code gets this far it worked.
  }

The code it generates for Scala3 uses defs instead of lazy vals - and passes that simple test

  implicit def controllerServiceReferencingComponentDTOTapirSchema: sttp.tapir.Schema[ControllerServiceReferencingComponentDTO] = sttp.tapir.Schema.derived
  implicit def controllerServiceReferencingComponentEntityTapirSchema: sttp.tapir.Schema[ControllerServiceReferencingComponentEntity] = sttp.tapir.Schema.derived

I'm generating this code from NiFi's OpenApi spec, after stripping out anything problematic to Tapir, and all the security business. Reproducing that hairball would be a lot of work, and would likely bury the problem. I could try to refine it but I don't know what I might be looking for.

I'm hoping Tapir fixed a bug for Scala3 that is easy to port to Scala2.13.

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