Skip to content

Commit

Permalink
airframe-http-codegen: Scala 3 support (#2668)
Browse files Browse the repository at this point in the history
- Do not support reflection-based Routers in Scala 3. Will provide a
Java-reflection based approach to find `object Api { def defaultRouter:
Router[Api] = Router.of[API] }` in #2669
- Skip supporting default method parameters in Scala 3
- Add http-codegen to projectDotty
  • Loading branch information
xerial committed Dec 25, 2022
1 parent 473e6d3 commit 7b7c3c7
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package wvlet.airframe.http.codegen
import example.generic.{GenericRequestService, GenericService}
import wvlet.airframe.http.HttpMessage.{Request, Response}
import wvlet.airframe.http.Router
import wvlet.airspec.AirSpec

import scala.concurrent.Future
Expand All @@ -22,8 +23,7 @@ import scala.concurrent.Future
*/
class GenericServiceTest extends AirSpec {

private val router =
RouteScanner.buildRouter(Seq(classOf[GenericService[Future]]))
private val router = RouteScanner.buildRouter(Seq(classOf[GenericService[Future]]))

test("support F and Future return values in async clients") {
debug(router)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ trait GenericService[F[_]] {
def ops(in: String): Future[Response]

@Endpoint(path = "/v1/hello_ops2")
def ops2(in: String): F[Response]
def ops2(in2: String): F[Response]

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package wvlet.airframe.http.codegen
import example.grpc.{AliasTest, Greeter}
import example.rpc.RPCExample
import wvlet.airframe.http.Router
import wvlet.airspec.AirSpec

/**
Expand All @@ -22,23 +23,35 @@ class GrpcClientGeneratorTest extends AirSpec {

test("generate sync gRPC client") {
val code = HttpCodeGenerator.generate(
RouteScanner.buildRouter(Seq(classOf[RPCExample])),
if (isScala3) {
Router.of[RPCExample]
} else {
RouteScanner.buildRouter(Seq(classOf[RPCExample]))
},
HttpClientGeneratorConfig("example.api:grpc:example.api.client")
)
debug(code)
}

test("generate gRPC client") {
val code = HttpCodeGenerator.generate(
RouteScanner.buildRouter(Seq(classOf[Greeter])),
if (isScala3) {
Router.of[Greeter]
} else {
RouteScanner.buildRouter(Seq(classOf[Greeter]))
},
HttpClientGeneratorConfig("example.grpc:grpc")
)
debug(code)
}

test("resolve alias types") {
val code = HttpCodeGenerator.generate(
RouteScanner.buildRouter(Seq(classOf[AliasTest])),
if (isScala3) {
Router.of[AliasTest]
} else {
RouteScanner.buildRouter(Seq(classOf[AliasTest]))
},
HttpClientGeneratorConfig("example.grpc:grpc")
)
debug(code)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,12 @@ import wvlet.airspec.AirSpec
/**
*/
class HttpClientGeneratorTest extends AirSpec {
val router =
private val router = if (isScala3) {
// In Scala 3, reflection-based router will not be supported
Router.add[ResourceApi].add[QueryApi].add[BookApi]
} else {
RouteScanner.buildRouter(Seq(classOf[ResourceApi], classOf[QueryApi], classOf[BookApi]))
}

test("build router") {
debug(router)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,15 @@
package wvlet.airframe.http.codegen

import example.rpc.RPCExample
import wvlet.airframe.http.Router
import wvlet.airspec.AirSpec

class RPCClientGeneratorTest extends AirSpec {
private val router = RouteScanner.buildRouter(Seq(classOf[RPCExample]))
private val router = if (isScala3) {
Router.of[RPCExample]
} else {
RouteScanner.buildRouter(Seq(classOf[RPCExample]))
}

test("generate RPC client") {
val config = HttpClientGeneratorConfig("example.rpc:rpc")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,29 +291,6 @@ class OpenAPITest extends AirSpec {
| required: true
| schema:
| type: string""".stripMargin,
""" /v1/get3/{id}:
| get:
| summary: get3
| description: get3
| operationId: get3
| parameters:
| - name: id
| in: path
| required: true
| schema:
| type: integer
| format: int32
| - name: p1
| in: query
| required: true
| schema:
| type: string
| - name: p2
| in: query
| required: false
| schema:
| type: string
| default: foo""".stripMargin,
""" /v1/post1:
| post:
| summary: post1
Expand Down Expand Up @@ -552,6 +529,47 @@ class OpenAPITest extends AirSpec {
}
}

test("optional method parameter") {
if (isScala3) {
pending("Need to find default method parameter in Scala 3")
}

val methodOptParam = Seq(
""" /v1/get3/{id}:
| get:
| summary: get3
| description: get3
| operationId: get3
| parameters:
| - name: id
| in: path
| required: true
| schema:
| type: integer
| format: int32
| - name: p1
| in: query
| required: true
| schema:
| type: string
| - name: p2
| in: query
| required: false
| schema:
| type: string
| default: foo""".stripMargin
)

methodOptParam.foreach { x =>
try {
yaml.contains(x) shouldBe true
} catch {
case e: Throwable =>
fail(s"Missing YAML fragment for:\n${x}")
}
}
}

// Parsing test
OpenAPI.parseJson(json)
val oa = parseOpenAPI(yaml)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -770,7 +770,9 @@ private[surface] class CompileTimeSurfaceFactory[Q <: Quotes](using quotes: Q) {
!x.flags.is(Flags.Synthetic) &&
!x.flags.is(Flags.Macro) &&
!x.flags.is(Flags.Implicit) &&
!x.flags.is(Flags.FieldAccessor)
!x.flags.is(Flags.FieldAccessor) &&
// Exclude methods from Java
!x.flags.is(Flags.JavaDefined)
}
.filter { x =>
val name = x.name
Expand Down
4 changes: 1 addition & 3 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -264,8 +264,7 @@ lazy val projectDotty =
fluentd,
http.jvm,
httpRouter,
// Surface.of(Class[_]) needs to be supported
// httpCodeGen
httpCodeGen,
// Finagle is used in the http recorder
// httpRecorder
// // Finagle isn't supporting Scala 3
Expand Down Expand Up @@ -678,7 +677,6 @@ lazy val httpCodeGen =
.in(file("airframe-http-codegen"))
.enablePlugins(PackPlugin)
.settings(buildSettings)
.settings(scala2Only)
.settings(
name := "airframe-http-codegen",
description := "REST and RPC code generator",
Expand Down

0 comments on commit 7b7c3c7

Please sign in to comment.