未验证 提交 8e4da614 编写于 作者: 梦境迷离's avatar 梦境迷离 提交者: GitHub

`ProcessorCreator` Macro (#125)

 use ProcessorCreator, remove Processor
上级 90795f24
......@@ -19,14 +19,14 @@ lazy val root = (project in file("."))
libraryDependencies ++= Seq(
"org.scala-lang" % "scala-compiler" % scalaVersion.value,
"org.scala-lang" % "scala-reflect" % scalaVersion.value,
"com.alipay.sofa" % "jraft-core" % "1.3.9",
"com.typesafe.scala-logging" %% "scala-logging" % "3.9.4",
"org.apache.logging.log4j" % "log4j-api" % "2.14.1" % Test,
"org.apache.logging.log4j" % "log4j-core" % "2.14.1" % Test,
"org.apache.logging.log4j" % "log4j-slf4j-impl" % "2.14.1" % Test,
"com.typesafe.play" %% "play-json" % "2.7.4" % Test,
"org.scalatest" %% "scalatest" % "3.2.10" % Test,
"com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.13.0" % Test
"com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.13.0" % Test,
"com.alipay.sofa" % "jraft-core" % "1.3.9" % Test
), Compile / scalacOptions ++= {
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, n)) if n <= 12 => Nil
......
......@@ -19,43 +19,55 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.dreamylost.sofa
package io.github.dreamylost
import com.alipay.sofa.jraft.rpc.{ RpcContext, RpcRequestClosure, RpcRequestProcessor }
import com.google.protobuf.Message
import com.typesafe.scalalogging.LazyLogging
import io.github.dreamylost.macros.ProcessorCreatorMacro
import java.util.concurrent.Executor
import scala.reflect.ClassTag
/**
* Common processor
* The macro util to generate processor for alipay sofa jraft rpc.
*
* @param executor The executor used to execute the specified sofa RPC request
* @param defaultResp Default message instance for sofa
* @tparam Req The Request proto message for sofa
* @author 梦境迷离
* @version 1.0,2021/12/3
* @version 1.0,2021/12/6
*/
abstract class CustomRpcProcessor[Req <: Message](executor: Executor, override val defaultResp: Message)(implicit reqClassTag: ClassTag[Req])
extends RpcRequestProcessor[Req](executor, defaultResp) with LazyLogging {
object ProcessorCreator {
override def handleRequest(rpcCtx: RpcContext, request: Req) {
try {
val msg = processRequest(request, new RpcRequestClosure(rpcCtx, this.defaultResp))
if (msg != null) {
rpcCtx.sendResponse(msg)
}
} catch {
case e: Exception =>
logger.error(s"handleRequest $request failed", e)
rpcCtx.sendResponse(processError(rpcCtx, e))
}
}
/**
*
* @param service Instance of the [[Service]]
* @param defaultResp Default instance of the Response Message
* @param executor Instance of the Executor
* @param processRequest Function to handle request
* @param processException Function to handle exception
* @tparam RRC RpcRequestClosure
* @tparam RRP RpcRequestProcessor
* @tparam RC RpcContext
* @tparam Req Request Message of the protobuf
* @tparam Resp Response Message of the protobuf
* @tparam Service Should be custom class/interface/trait which handle the business logic of Processors
* @tparam E Should be subclass of the Executor
* @return [[ RRP ]] Instance of the RpcRequestProcessor subclass
*/
def apply[RRC, RRP[_ <: Req], RC, Req, Resp, Service, E <: Executor]
(
defaultResp: Resp,
processRequest: (Service, RRC, Req) Resp,
processException: (Service, RC, Exception) Resp
)(implicit service: Service, executor: E): RRP[Req] = macro ProcessorCreatorMacro.SimpleImpl[RRC, RRP[_ <: Req], RC, Req, Resp, Service, E]
def processError(rpcCtx: RpcContext, exception: Exception): Message
def apply[RRC, RRP[_ <: Req], RC, Req, Resp, Service]
(
processRequest: (Service, RRC, Req) Resp,
processException: (Service, RC, Exception) Resp
)(implicit service: Service): RRP[Req] = macro ProcessorCreatorMacro.WithoutExecutorAndDefaultResp[RRC, RRP[_ <: Req], RC, Req, Resp, Service]
override def interest(): String = {
reqClassTag.runtimeClass.getName
}
/**
* Having two identical type parameters will cause the compiler to recognize error and change the order of generics to avoid.
*/
def apply[Service, RRC, RRP[_ <: Req], RC, Req, Resp]
(
processRequest: (Service, RRC, Req) Resp,
processException: (Service, RC, Exception) Resp
): RRP[Req] = macro ProcessorCreatorMacro.OnlyWithFunctionalParameters[Service, RRC, RRP[_ <: Req], RC, Req, Resp]
}
......@@ -22,7 +22,6 @@
package io.github.dreamylost.macros
import scala.reflect.runtime.currentMirror
import scala.reflect.runtime.universe.typeTag
import scala.reflect.runtime.universe._
/**
......
......@@ -20,7 +20,6 @@
*/
package io.github.dreamylost.macros
import scala.collection.mutable
object MacroCache {
......
......@@ -19,128 +19,160 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.dreamylost.sofa
import com.alipay.sofa.jraft.rpc.{ RpcContext, RpcRequestClosure }
import com.google.protobuf.Message
import io.github.dreamylost.macros.MacroCache
package io.github.dreamylost.macros
import scala.reflect.macros.blackbox
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
import scala.reflect.macros.blackbox
/**
* Processable macro
*
* @author 梦境迷离
* @since 2021/12/4
* @version 1.0
* @version 1.0,2021/12/6
*/
object ProcessableMacro {
object ProcessorCreatorMacro {
private val classNamePrefix: String = "AnonProcessor$"
def processorWithDefaultRespServiceImpl[Req <: Message: c.WeakTypeTag, Resp <: Message: c.WeakTypeTag, Service: c.WeakTypeTag]
def SimpleImpl[RRC: c.WeakTypeTag, RRP: c.WeakTypeTag, RC: c.WeakTypeTag, Req: c.WeakTypeTag, Resp: c.WeakTypeTag, Service: c.WeakTypeTag, E: c.WeakTypeTag]
(c: blackbox.Context)
(
processRequest: c.Expr[(Service, RpcRequestClosure, Req) Req],
processException: c.Expr[(Service, RpcContext, Exception) Req]
): c.Expr[CustomRpcProcessor[Req]] = {
defaultResp: c.Expr[Req],
processRequest: c.Expr[(Service, RRC, Req) Req],
processException: c.Expr[(Service, RC, Exception) Req]
)(service: c.Expr[Service], executor: c.Expr[E]): c.Expr[RRP] = { // parameters in order, parameter names differ will compile error
import c.universe._
val serviceType = weakTypeOf[Service]
if (serviceType.typeSymbol.isAbstract || !serviceType.typeSymbol.isClass) {
c.abort(c.enclosingPosition, "Not support for abstract classes")
}
if (serviceType.typeSymbol.isModuleClass) {
c.abort(c.enclosingPosition, "Not support for module classes")
}
val className = TypeName(classNamePrefix + MacroCache.getIdentityId)
val reqProtoType = weakTypeOf[Req]
val respProtoType = weakTypeOf[Resp].companion //getDefaultInstance is static method, it's in companion
val rpcRequestClosureType = weakTypeOf[RRC]
val rpcContextType = weakTypeOf[RC]
val respProtoType = weakTypeOf[Resp]
val processor =
q"""
class $className(private val service: $serviceType, executor: java.util.concurrent.Executor = null)
extends io.github.dreamylost.sofa.CustomRpcProcessor[$reqProtoType](executor, $respProtoType.getDefaultInstance) {
extends com.alipay.sofa.jraft.rpc.RpcRequestProcessor[$reqProtoType](executor, $defaultResp) with com.typesafe.scalalogging.LazyLogging {
override def handleRequest(rpcCtx: com.alipay.sofa.jraft.rpc.RpcContext, request: $reqProtoType) {
try {
val msg = processRequest(request, new com.alipay.sofa.jraft.rpc.RpcRequestClosure(rpcCtx, this.defaultResp))
if (msg != null) {
rpcCtx.sendResponse(msg)
}
} catch {
case e: Exception =>
logger.error("handleRequest" + request + "failed", e)
rpcCtx.sendResponse(processError(rpcCtx, e))
}
}
override def interest(): String = classOf[$reqProtoType].getName
override def processRequest(request: $reqProtoType, done: com.alipay.sofa.jraft.rpc.RpcRequestClosure): com.google.protobuf.Message = {
$processRequest(service, done, request)
}
def processRequest(request: $reqProtoType, done: $rpcRequestClosureType): $respProtoType = {
$processRequest(service, done, request)
}
override def processError(rpcCtx: com.alipay.sofa.jraft.rpc.RpcContext, exception: Exception): com.google.protobuf.Message = {
$processException(service, rpcCtx, exception)
}
def processError(rpcCtx: $rpcContextType, exception: Exception): $respProtoType = {
$processException(service, rpcCtx, exception)
}
}
val service = new io.github.dreamylost.macros.Creator[$serviceType].createInstance(null)(0)
new $className(service, null)
new $className($service, $executor)
"""
printTree[Req](c)(processor)
printTree[RRP](c)(processor)
}
def processorWithDefaultRespImpl[Service: c.WeakTypeTag, Req <: Message: c.WeakTypeTag, Resp <: Message: c.WeakTypeTag]
(c: blackbox.Context)
(service: c.Expr[Service])
(
processRequest: c.Expr[(Service, RpcRequestClosure, Req) Req],
processException: c.Expr[(Service, RpcContext, Exception) Req]
): c.Expr[CustomRpcProcessor[Req]] = {
def WithoutExecutorAndDefaultResp[RRC: c.WeakTypeTag, RRP: c.WeakTypeTag, RC: c.WeakTypeTag, Req: c.WeakTypeTag, Resp: c.WeakTypeTag, Service: c.WeakTypeTag]
(c: blackbox.Context)(
processRequest: c.Expr[(Service, RRC, Req) Req],
processException: c.Expr[(Service, RC, Exception) Req]
)(service: c.Expr[Service]): c.Expr[RRP] = {
import c.universe._
val className = TypeName(classNamePrefix + MacroCache.getIdentityId)
checkTree[RRC, RRP, RC, Service](c)
val serviceType = weakTypeOf[Service]
val className = TypeName(classNamePrefix + MacroCache.getIdentityId)
val reqProtoType = weakTypeOf[Req]
val respProtoType = weakTypeOf[Resp].companion //getDefaultInstance is static method, it's in companion
val rpcRequestClosureType = weakTypeOf[RRC]
val rpcContextType = weakTypeOf[RC]
val respProtoType = weakTypeOf[Resp]
val respProtoCompanionType = weakTypeOf[Resp].companion //getDefaultInstance is static method, it's in companion
val processor =
q"""
class $className(private val service: $serviceType, executor: java.util.concurrent.Executor = null)
extends io.github.dreamylost.sofa.CustomRpcProcessor[$reqProtoType](executor, $respProtoType.getDefaultInstance) {
extends com.alipay.sofa.jraft.rpc.RpcRequestProcessor[$reqProtoType](executor, $respProtoCompanionType.getDefaultInstance)
with com.typesafe.scalalogging.LazyLogging {
override def handleRequest(rpcCtx: com.alipay.sofa.jraft.rpc.RpcContext, request: $reqProtoType) {
try {
val msg = processRequest(request, new com.alipay.sofa.jraft.rpc.RpcRequestClosure(rpcCtx, this.defaultResp))
if (msg != null) {
rpcCtx.sendResponse(msg)
}
} catch {
case e: Exception =>
logger.error("handleRequest" + request + "failed", e)
rpcCtx.sendResponse(processError(rpcCtx, e))
}
}
override def interest(): String = classOf[$reqProtoType].getName
override def processRequest(request: $reqProtoType, done: com.alipay.sofa.jraft.rpc.RpcRequestClosure): com.google.protobuf.Message = {
$processRequest(service, done, request)
}
def processRequest(request: $reqProtoType, done: $rpcRequestClosureType): $respProtoType = {
$processRequest(service, done, request)
}
override def processError(rpcCtx: com.alipay.sofa.jraft.rpc.RpcContext, exception: Exception): com.google.protobuf.Message = {
$processException(service, rpcCtx, exception)
}
def processError(rpcCtx: $rpcContextType, exception: Exception): $respProtoType = {
$processException(service, rpcCtx, exception)
}
}
new $className($service, null)
new $className($service)
"""
printTree[Req](c)(processor)
printTree[RRP](c)(processor)
}
def processorImpl[Req <: Message: c.WeakTypeTag, Service: c.WeakTypeTag, Executor: c.WeakTypeTag]
(c: blackbox.Context)
(
service: c.Expr[Service],
defaultResp: c.Expr[Req],
executor: c.Expr[Executor]
)
(
processRequest: c.Expr[(Service, RpcRequestClosure, Req) Req],
processException: c.Expr[(Service, RpcContext, Exception) Req]
): c.Expr[CustomRpcProcessor[Req]] = {
def OnlyWithFunctionalParameters[Service: c.WeakTypeTag, RRC: c.WeakTypeTag, RRP: c.WeakTypeTag, RC: c.WeakTypeTag, Req: c.WeakTypeTag, Resp: c.WeakTypeTag]
(c: blackbox.Context)(
processRequest: c.Expr[(Service, RRC, Req) Req],
processException: c.Expr[(Service, RC, Exception) Req]
): c.Expr[RRP] = {
import c.universe._
val className = TypeName(classNamePrefix + MacroCache.getIdentityId)
checkTree[RRC, RRP, RC, Service](c)
val serviceType = weakTypeOf[Service]
val requestProtoType = weakTypeOf[Req]
val className = TypeName(classNamePrefix + MacroCache.getIdentityId)
val reqProtoType = weakTypeOf[Req]
val rpcRequestClosureType = weakTypeOf[RRC]
val rpcContextType = weakTypeOf[RC]
val respProtoType = weakTypeOf[Resp]
val respProtoCompanionType = weakTypeOf[Resp].companion //getDefaultInstance is static method, it's in companion
val processor =
q"""
class $className(private val service: $serviceType, executor: java.util.concurrent.Executor = null)
extends io.github.dreamylost.sofa.CustomRpcProcessor[$requestProtoType](executor, $defaultResp) {
extends com.alipay.sofa.jraft.rpc.RpcRequestProcessor[$reqProtoType](executor, $respProtoCompanionType.getDefaultInstance)
with com.typesafe.scalalogging.LazyLogging {
override def handleRequest(rpcCtx: com.alipay.sofa.jraft.rpc.RpcContext, request: $reqProtoType) {
try {
val msg = processRequest(request, new com.alipay.sofa.jraft.rpc.RpcRequestClosure(rpcCtx, this.defaultResp))
if (msg != null) {
rpcCtx.sendResponse(msg)
}
} catch {
case e: Exception =>
logger.error("handleRequest" + request + "failed", e)
rpcCtx.sendResponse(processError(rpcCtx, e))
}
}
override def interest(): String = classOf[$reqProtoType].getName
override def processRequest(request: $requestProtoType, done: com.alipay.sofa.jraft.rpc.RpcRequestClosure): com.google.protobuf.Message = {
$processRequest(service, done, request)
}
def processRequest(request: $reqProtoType, done: $rpcRequestClosureType): $respProtoType = {
$processRequest(service, done, request)
}
override def processError(rpcCtx: com.alipay.sofa.jraft.rpc.RpcContext, exception: Exception): com.google.protobuf.Message = {
$processException(service, rpcCtx, exception)
}
def processError(rpcCtx: $rpcContextType, exception: Exception): $respProtoType = {
$processException(service, rpcCtx, exception)
}
}
new $className($service, $executor)
val service = new io.github.dreamylost.macros.Creator[$serviceType].createInstance(null)(0)
new $className(service)
"""
printTree[Req](c)(processor)
printTree[RRP](c)(processor)
}
private def printTree[Req <: Message](c: blackbox.Context)(processor: c.Tree): c.Expr[CustomRpcProcessor[Req]] = {
val ret = c.Expr[CustomRpcProcessor[Req]](processor)
private def printTree[RRP](c: blackbox.Context)(processor: c.Tree): c.Expr[RRP] = {
val ret = c.Expr[RRP](processor)
c.info(
c.enclosingPosition,
s"\n###### Time: ${
......@@ -151,4 +183,23 @@ object ProcessableMacro {
)
ret
}
private def checkTree[RRC: c.WeakTypeTag, RRP: c.WeakTypeTag, RC: c.WeakTypeTag, Service: c.WeakTypeTag](c: blackbox.Context): Unit = {
import c.universe._
val serviceType = weakTypeOf[Service]
if (serviceType.typeSymbol.isAbstract || !serviceType.typeSymbol.isClass) {
c.abort(c.enclosingPosition, "Not support for abstract classes")
}
if (serviceType.typeSymbol.isModuleClass) {
c.abort(c.enclosingPosition, "Not support for module classes")
}
val rpcRequestClosureType = weakTypeOf[RRC]
if (!rpcRequestClosureType.resultType.toString.equals("com.alipay.sofa.jraft.rpc.RpcRequestClosure")) {
c.abort(c.enclosingPosition, s"`RRC` only support for `com.alipay.sofa.jraft.rpc.RpcRequestClosure`, not `${rpcRequestClosureType.resultType.toString}`")
}
val rpcContextType = weakTypeOf[RC]
if (!rpcContextType.resultType.toString.equals("com.alipay.sofa.jraft.rpc.RpcContext")) {
c.abort(c.enclosingPosition, s"`RRC` only support for `com.alipay.sofa.jraft.rpc.RpcContext`, not `${rpcContextType.resultType.toString}`")
}
}
}
/*
* Copyright (c) 2021 jxnu-liguobin && contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package io.github.dreamylost.sofa
import com.alipay.sofa.jraft.rpc.{ RpcContext, RpcRequestClosure }
import com.google.protobuf.Message
/**
* The Processable util to generate processor for alipay sofa jraft rpc.
*
* @author 梦境迷离
* @version 1.0,2021/12/3
*/
object Processable {
def apply[Req <: Message, Service, Executor <: java.util.concurrent.Executor]
(service: Service, defaultResp: Message, executor: Executor)
(
processRequest: (Service, RpcRequestClosure, Req) Message,
processException: (Service, RpcContext, Exception) Message): CustomRpcProcessor[Req] = macro ProcessableMacro.processorImpl[Req, Service, Executor]
def apply[Service, Req <: Message, Resp <: Message](service: Service)
(
processRequest: (Service, RpcRequestClosure, Req) Message,
processException: (Service, RpcContext, Exception) Message): CustomRpcProcessor[Req] = macro ProcessableMacro.processorWithDefaultRespImpl[Service, Req, Resp]
def apply[Req <: Message, Resp <: Message, Service]
(
processRequest: (Service, RpcRequestClosure, Req) Message,
processException: (Service, RpcContext, Exception) Message): CustomRpcProcessor[Req] = macro ProcessableMacro.processorWithDefaultRespServiceImpl[Req, Resp, Service]
}
//Test for Processable
//Test for Processable and ProcessorCreator
syntax = "proto3";
option java_package = "io.github.dreamylost.test.proto";
......
......@@ -21,59 +21,38 @@
package io.github.dreamylost
import com.alipay.sofa.jraft.rpc.{ RpcContext, RpcRequestClosure }
import com.alipay.sofa.jraft.rpc.{ RpcContext, RpcRequestClosure, RpcRequestProcessor }
import io.github.dreamylost.test.proto.BOpenSession.{ BOpenSessionReq, BOpenSessionResp }
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import java.util.concurrent.Executor
import io.github.dreamylost.sofa.Processable
import scala.jdk.CollectionConverters.MapHasAsScala
import io.github.dreamylost.sofa.CustomRpcProcessor
/**
*
* @author 梦境迷离
* @version 1.0,2021/12/3
* @version 1.0,2021/12/6
*/
class ProcessableTest extends AnyFlatSpec with Matchers {
class ProcessorCreatorTest extends AnyFlatSpec with Matchers {
// please exec `sbt compile` to generate java class fof the protobuf
// origin
"Processable1" should "compile ok" in {
val openSession: CustomRpcProcessor[BOpenSessionReq] = Processable[BOpenSessionReq, NetService, Executor](
new NetService, BOpenSessionResp.getDefaultInstance, (command: Runnable) => ???
)(
(service, rpcRequestClosure, req) => {
import scala.jdk.CollectionConverters.MapHasAsScala
val username = req.getUsername
val password = req.getPassword
val configurationMap = req.getConfigurationMap
val ret = service.openSession(username, password, configurationMap.asScala.toMap)
BOpenSessionResp.newBuilder().setSessionHandle(ret).build()
},
(service, rpcContext, exception) => {
BOpenSessionResp.newBuilder().setStatus(exception.getLocalizedMessage).build()
}
)
println(openSession.defaultResp)
println(openSession.getClass.getClass.getName)
println(openSession.interest())
}
// // simple v1
"Processable2" should "compile ok" in {
val openSession: CustomRpcProcessor[BOpenSessionReq] = Processable[NetService, BOpenSessionReq, BOpenSessionResp](new NetService)(
(service, _, req) => {
"ProcessorCreator1" should "compile ok" in {
implicit val service = new NetService
implicit val executor: Executor = new Executor {
override def execute(command: Runnable): Unit = ()
}
val openSession = ProcessorCreator[RpcRequestClosure, RpcRequestProcessor, RpcContext, BOpenSessionReq, BOpenSessionResp, NetService, Executor](
BOpenSessionResp.getDefaultInstance,
(service, rpcRequestClosure, req) => {
import scala.jdk.CollectionConverters.MapHasAsScala
val username = req.getUsername
val password = req.getPassword
val configurationMap = req.getConfigurationMap
val ret = service.openSession(username, password, configurationMap.asScala.toMap)
BOpenSessionResp.newBuilder().setSessionHandle(ret).build()
},
(_, _, exception) => {
(service, rpcContext, exception) => {
BOpenSessionResp.newBuilder().setStatus(exception.getLocalizedMessage).build()
}
)
......@@ -85,11 +64,11 @@ class ProcessableTest extends AnyFlatSpec with Matchers {
println(openSession.interest())
}
// simple v2
"Processable3" should "compile ok" in {
// NetService must be a class and with an no parameter construction
val openSession: CustomRpcProcessor[BOpenSessionReq] = Processable[BOpenSessionReq, BOpenSessionResp, NetService](
(service: NetService, rpc: RpcRequestClosure, req: BOpenSessionReq) => {
// simple v1
"ProcessorCreator2" should "compile ok" in {
implicit val service = new NetService
val openSession = ProcessorCreator[RpcRequestClosure, RpcRequestProcessor, RpcContext, BOpenSessionReq, BOpenSessionResp, NetService](
(service, _, req) => {
import scala.jdk.CollectionConverters.MapHasAsScala
val username = req.getUsername
val password = req.getPassword
......@@ -97,7 +76,7 @@ class ProcessableTest extends AnyFlatSpec with Matchers {
val ret = service.openSession(username, password, configurationMap.asScala.toMap)
BOpenSessionResp.newBuilder().setSessionHandle(ret).build()
},
(service: NetService, rpc: RpcContext, exception: Exception) => {
(_, _, exception) => {
BOpenSessionResp.newBuilder().setStatus(exception.getLocalizedMessage).build()
}
)
......@@ -110,10 +89,11 @@ class ProcessableTest extends AnyFlatSpec with Matchers {
}
// simple v2
"Processable4" should "compile ok" in {
"ProcessorCreator3" should "compile ok" in {
// NetService must be a class and with an no parameter construction
val openSession: CustomRpcProcessor[BOpenSessionReq] = Processable[BOpenSessionReq, BOpenSessionResp, NetService](
val openSession = ProcessorCreator[NetService, RpcRequestClosure, RpcRequestProcessor, RpcContext, BOpenSessionReq, BOpenSessionResp](
(service, rpc, req) => {
import scala.jdk.CollectionConverters.MapHasAsScala
val username = req.getUsername
val password = req.getPassword
val configurationMap = req.getConfigurationMap
......@@ -132,4 +112,66 @@ class ProcessableTest extends AnyFlatSpec with Matchers {
println(openSession.interest())
}
// error
"ProcessorCreator4" should "compile error" in {
trait Service
"""
| val openSession = ProcessorCreator[Service, RpcRequestClosure, RpcRequestProcessor, RpcContext, BOpenSessionReq, BOpenSessionResp](
| (service, rpc, req) => {
| BOpenSessionResp.newBuilder().setSessionHandle(null).build()
| },
| (service, rpc, exception) => {
| BOpenSessionResp.newBuilder().setStatus(exception.getLocalizedMessage).build()
| }
| )
|
| println(openSession.defaultResp)
|
| println(openSession.getClass.getClass.getName)
|
| println(openSession.interest())
|""".stripMargin shouldNot compile
}
// error
"ProcessorCreator5" should "compile error" in {
trait Service
"""
| val openSession = ProcessorCreator[Service, RpcRequestProcessor, RpcRequestClosure, RpcContext, BOpenSessionReq, BOpenSessionResp](
| (service, rpc, req) => {
| BOpenSessionResp.newBuilder().setSessionHandle(null).build()
| },
| (service, rpc, exception) => {
| BOpenSessionResp.newBuilder().setStatus(exception.getLocalizedMessage).build()
| }
| )
|
| println(openSession.defaultResp)
|
| println(openSession.getClass.getClass.getName)
|
| println(openSession.interest())
|""".stripMargin shouldNot compile
}
// error
"ProcessorCreator6" should "compile error" in {
object Service
"""
| val openSession = ProcessorCreator[Service, RpcRequestClosure, RpcRequestProcessor, RpcContext, BOpenSessionReq, BOpenSessionResp](
| (service, rpc, req) => {
| BOpenSessionResp.newBuilder().setSessionHandle(null).build()
| },
| (service, rpc, exception) => {
| BOpenSessionResp.newBuilder().setStatus(exception.getLocalizedMessage).build()
| }
| )
|
| println(openSession.defaultResp)
|
| println(openSession.getClass.getClass.getName)
|
| println(openSession.interest())
|""".stripMargin shouldNot compile
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册