Skip to content

Commit

Permalink
codec (fix): Support Scala 3 Enum in AnyCodec to make RPC work (#3276)
Browse files Browse the repository at this point in the history
Fixes #3275
  • Loading branch information
xerial authored Nov 12, 2023
1 parent b13f5a3 commit 4370db2
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 30 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package wvlet.airframe.codec

trait AnyCodecCompat {
protected def isEnum(o: Any): Boolean = false
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package wvlet.airframe.codec

trait AnyCodecCompat {
protected def isEnum(o: Any): Boolean = {
o match {
case _: scala.runtime.EnumValue => true
case _ => false
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -923,7 +923,8 @@ object PrimitiveCodec {
class AnyCodec(
codecFactory: MessageCodecFactory = MessageCodecFactory.defaultFactoryForJSON,
knownSurfaces: Seq[Surface] = Seq.empty
) extends MessageCodec[Any] {
) extends MessageCodec[Any]
with AnyCodecCompat {

private val knownSurfaceTable = knownSurfaces.map(s => s.rawType -> s).toMap[Class[_], Surface]

Expand Down Expand Up @@ -991,6 +992,9 @@ object PrimitiveCodec {
}
case v: Throwable =>
ThrowableCodec.pack(p, v)
case e if isEnum(e) =>
// Scala 3 EnumValue
StringCodec.pack(p, e.toString)
case _ =>
val cl = v.getClass
knownSurfaceTable.get(cl) match {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
*/
package wvlet.airframe.codec

import wvlet.airframe.codec.PrimitiveCodec.AnyCodec
import wvlet.airframe.json.JSON
import wvlet.airframe.msgpack.spi.MessagePack
import wvlet.airspec.AirSpec
Expand Down Expand Up @@ -70,3 +71,9 @@ object Scala3EnumCodecTest extends AirSpec:
val json = codec.toJson(p)
json shouldBe """{}"""
}

test("Pack with AnyCodec") {
val codec = AnyCodec.default
val msgpack = codec.toMsgPack(Color.Green)
MessageCodec.of[Color].unpack(msgpack) shouldBe Color.Green
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,24 +35,8 @@ object HelloRPC extends RxRouterProvider {
)
}

sealed trait Status {
def isDone: Boolean

def name: String = toString
}

object Status {
case object OK extends Status {
override def isDone: Boolean = true
}

case object NG extends Status {
override def isDone: Boolean = true
}

def all: Seq[Status] = Seq(OK, NG)

def unapply(s: String): Option[Status] = {
all.find(_.toString == s)
}
enum Status(isDone: Boolean) {
def name: String = this.toString
case OK extends Status(isDone = true)
case NG extends Status(isDone = true)
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import wvlet.airframe.Design
import wvlet.airframe.http.{Http, RPCEncoding, RxRouter}
import wvlet.airframe.http.netty.{Netty, NettyServer}
import wvlet.airframe.test.api.HelloRPC.VariousParams
import wvlet.airframe.test.api.Status
import wvlet.airspec.AirSpec

class HelloRPCTest extends AirSpec {
Expand Down
23 changes: 15 additions & 8 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,11 @@ val scala2Only = Seq[Setting[_]](
crossScalaVersions := uptoScala2
)

val scala3Only = Seq[Setting[_]](
scalaVersion := SCALA_3,
crossScalaVersions := List(SCALA_3)
)

// Do not run tests concurrently to avoid JMX registration failures
val runTestSequentially = Seq[Setting[_]](Test / parallelExecution := false)

Expand Down Expand Up @@ -225,9 +230,7 @@ lazy val jvmProjects: Seq[ProjectReference] = communityBuildProjects ++ Seq[Proj
finagle,
benchmark,
sql,
examples,
integrationTestApi,
integrationTest
examples
)

// Scala.js build (Scala 2.12, 2.13, and 3.x)
Expand Down Expand Up @@ -316,7 +319,9 @@ lazy val projectDotty =
rx.jvm,
rxHtml.jvm,
sql,
ulid.jvm
ulid.jvm,
integrationTestApi,
integrationTest
)

lazy val docs =
Expand Down Expand Up @@ -1007,28 +1012,30 @@ lazy val dottyTest =
)
.dependsOn(log.jvm, surface.jvm, di.jvm, codec.jvm)

// Integration test for Scala 3
lazy val integrationTestApi =
project
.in(file("airframe-integration-test-api"))
.settings(buildSettings)
.settings(noPublish)
.settings(
name := "airframe-integration-test-api",
description := "APIs for integration test",
crossScalaVersions := targetScalaVersions
scala3Only,
name := "airframe-integration-test-api",
description := "APIs for integration test"
)
.dependsOn(http.jvm)

// Integration test for Scala 3
lazy val integrationTest =
project
.in(file("airframe-integration-test"))
.enablePlugins(AirframeHttpPlugin)
.settings(buildSettings)
.settings(noPublish)
.settings(
scala3Only,
name := "airframe-integration-test",
description := "integration test project",
crossScalaVersions := targetScalaVersions,
airframeHttpClients := Seq("wvlet.airframe.test.api:rpc")
)
.dependsOn(integrationTestApi, netty)

0 comments on commit 4370db2

Please sign in to comment.