Skip to content

Commit cd32101

Browse files
authored
Retrieve fields via apply method when possible (#169)
which is the only option if the case class is defined nested within an object.
1 parent 8bdb0ce commit cd32101

File tree

3 files changed

+56
-5
lines changed

3 files changed

+56
-5
lines changed

src/main/scala-2/com/github/swagger/scala/converter/ErasureHelper.scala

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,26 @@
11
package com.github.swagger.scala.converter
22

3+
import scala.reflect.runtime.universe.TermName
4+
35
object ErasureHelper {
46

57
def erasedOptionalPrimitives(cls: Class[_]): Map[String, Class[_]] = {
68
import scala.reflect.runtime.universe
79
val mirror = universe.runtimeMirror(cls.getClassLoader)
8-
val sym = mirror.staticClass(cls.getName)
9-
val properties = sym.selfType.members
10-
.filterNot(_.isMethod)
11-
.filterNot(_.isClass)
1210

13-
properties.flatMap { prop =>
11+
val moduleSymbol = mirror.moduleSymbol(Class.forName(cls.getName))
12+
val ConstructorName = "apply"
13+
val companion: universe.Symbol = moduleSymbol.typeSignature.member(TermName(ConstructorName))
14+
val properties = if (companion.fullName.endsWith(ConstructorName)) {
15+
companion.asMethod.paramLists.flatten
16+
} else {
17+
val sym = mirror.staticClass(cls.getName)
18+
sym.selfType.members
19+
.filterNot(_.isMethod)
20+
.filterNot(_.isClass)
21+
}
22+
23+
properties.flatMap { prop: universe.Symbol =>
1424
val maybeClass: Option[Class[_]] = prop.typeSignature.typeArgs.headOption.flatMap { signature =>
1525
if (signature.typeSymbol.isClass) {
1626
Option(mirror.runtimeClass(signature.typeSymbol.asClass))

src/test/scala/com/github/swagger/scala/converter/ModelPropertyParserTest.scala

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.github.swagger.scala.converter
33
import io.swagger.v3.core.converter._
44
import io.swagger.v3.core.util.Json
55
import io.swagger.v3.oas.models.media._
6+
import models.NestingObject.NestedModelWOptionInt
67
import models._
78
import org.scalatest.OptionValues
89
import org.scalatest.flatspec.AnyFlatSpec
@@ -117,6 +118,41 @@ class ModelPropertyParserTest extends AnyFlatSpec with Matchers with OptionValue
117118
nullSafeList(model.value.getRequired) shouldBe empty
118119
}
119120

121+
it should "process Model with nested Scala Option Int" in {
122+
val converter = ModelConverters.getInstance()
123+
val schemas = converter.readAll(classOf[NestedModelWOptionInt]).asScala.toMap
124+
val model = schemas.get("NestedModelWOptionInt")
125+
model should be(defined)
126+
model.value.getProperties should not be (null)
127+
val optInt = model.value.getProperties().get("optInt")
128+
optInt should not be (null)
129+
if (RuntimeUtil.isScala3()) {
130+
optInt shouldBe a[ObjectSchema]
131+
} else {
132+
optInt shouldBe a[IntegerSchema]
133+
optInt.asInstanceOf[IntegerSchema].getFormat shouldEqual "int32"
134+
}
135+
nullSafeList(model.value.getRequired) shouldBe empty
136+
}
137+
138+
it should "process Model with nested Scala Option Int with Schema Override" in {
139+
val converter = ModelConverters.getInstance()
140+
val schemas = converter.readAll(classOf[ModelWOptionIntSchemaOverride]).asScala.toMap
141+
val model = schemas.get("ModelWOptionIntSchemaOverride")
142+
model should be(defined)
143+
model.value.getProperties should not be (null)
144+
val optInt = model.value.getProperties().get("optInt")
145+
optInt should not be (null)
146+
if (RuntimeUtil.isScala3()) {
147+
optInt shouldBe a[ObjectSchema]
148+
} else {
149+
optInt shouldBe a[IntegerSchema]
150+
optInt.asInstanceOf[IntegerSchema].getFormat shouldEqual "int32"
151+
}
152+
optInt.getDescription shouldBe "This is an optional int"
153+
nullSafeList(model.value.getRequired) shouldBe empty
154+
}
155+
120156
it should "process Model with Scala Option Int with Schema Override" in {
121157
val converter = ModelConverters.getInstance()
122158
val schemas = converter.readAll(classOf[ModelWOptionIntSchemaOverride]).asScala.toMap

src/test/scala/models/ModelWOptionInt.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ import io.swagger.v3.oas.annotations.media.Schema
44

55
case class ModelWOptionInt(optInt: Option[Int])
66

7+
object NestingObject {
8+
case class NestedModelWOptionInt(optInt: Option[Int])
9+
case class NestedModelWOptionIntSchemaOverride(@Schema(description = "This is an optional int") optInt: Option[Int])
10+
}
11+
712
case class ModelWOptionIntSchemaOverride(@Schema(description = "This is an optional int") optInt: Option[Int])
813

914
case class ModelWOptionIntSchemaOverrideForRequired(@Schema(required = true) optInt: Option[Int])

0 commit comments

Comments
 (0)