Skip to content

Commit d88cd87

Browse files
authored
Merge pull request #20 from shogowada/develop
Develop
2 parents 5dc0937 + 263fab7 commit d88cd87

File tree

8 files changed

+99
-22
lines changed

8 files changed

+99
-22
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ The library has no opinion about how the string should be passed between server
1010

1111
|Component|SBT|Scala Version|Scala JS Version|
1212
|---|---|---|---|
13-
|scala-json-rpc|```"io.github.shogowada" %%% "scala-json-rpc" % "0.4.0"```|2.12|0.6|
14-
|[scala-json-rpc-upickle-json-serializer](/upickle-json-serializer)|```"io.github.shogowada" %%% "scala-json-rpc-upickle-json-serializer" % "0.4.0"```|2.12|0.6|
13+
|scala-json-rpc|```"io.github.shogowada" %%% "scala-json-rpc" % "0.4.1"```|2.12|0.6|
14+
|[scala-json-rpc-upickle-json-serializer](/upickle-json-serializer)|```"io.github.shogowada" %%% "scala-json-rpc-upickle-json-serializer" % "0.4.1"```|2.12|0.6|
1515

1616
It supports the following features:
1717

build.sbt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ publishArtifact := false
1212
val commonSettings = Seq(
1313
organization := "io.github.shogowada",
1414
name := "scala-json-rpc",
15-
version := "0.4.0",
15+
version := "0.4.1",
1616
scalaVersion := "2.12.1",
1717
logBuffered in Test := false,
1818
licenses := Seq("MIT" -> url("https://opensource.org/licenses/MIT")),

shared/src/main/scala/io/github/shogowada/scala/jsonrpc/JsonRpcServerAndClient.scala

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,27 +32,45 @@ object JsonRpcServerAndClient {
3232
object JsonRpcServerAndClientMacro {
3333
def bindApi[API: c.WeakTypeTag](c: blackbox.Context)(api: c.Expr[API]): c.Expr[Unit] = {
3434
import c.universe._
35-
val server = q"${c.prefix.tree}.server"
36-
val client = q"${c.prefix.tree}.client"
37-
JsonRpcServerMacro.bindApiImpl[c.type, API](c)(server, Some(client), api)
35+
val macroUtils = JsonRpcMacroUtils[c.type](c)
36+
val (serverAndClientDefinition, serverAndClient) = macroUtils.prefixDefinitionAndReference
37+
val server = q"$serverAndClient.server"
38+
val client = q"$serverAndClient.client"
39+
val bindApi = JsonRpcServerMacro.bindApiImpl[c.type, API](c)(server, Some(client), api)
40+
c.Expr[Unit](
41+
q"""
42+
$serverAndClientDefinition
43+
$bindApi
44+
"""
45+
)
3846
}
3947

4048
def createApi[API: c.WeakTypeTag](c: blackbox.Context): c.Expr[API] = {
4149
import c.universe._
42-
val server = q"${c.prefix.tree}.server"
43-
val client = q"${c.prefix.tree}.client"
44-
JsonRpcClientMacro.createApiImpl[c.type, API](c)(client, Some(server))
50+
val macroUtils = JsonRpcMacroUtils[c.type](c)
51+
val (serverAndClientDefinition, serverAndClient) = macroUtils.prefixDefinitionAndReference
52+
val server = q"$serverAndClient.server"
53+
val client = q"$serverAndClient.client"
54+
val createApi = JsonRpcClientMacro.createApiImpl[c.type, API](c)(client, Some(server))
55+
c.Expr[API](
56+
q"""
57+
$serverAndClientDefinition
58+
$createApi
59+
"""
60+
)
4561
}
4662

4763
def receive(c: blackbox.Context)(json: c.Expr[String]): c.Expr[Unit] = {
4864
import c.universe._
4965
val macroUtils = JsonRpcMacroUtils[c.type](c)
50-
val client: Tree = q"${c.prefix.tree}.client"
51-
val server: Tree = q"${c.prefix.tree}.server"
66+
val (serverAndClientDefinition, serverAndClient) = macroUtils.prefixDefinitionAndReference
67+
val server: Tree = q"$serverAndClient.server"
68+
val client: Tree = q"$serverAndClient.client"
5269
val executionContext: c.Expr[ExecutionContext] = c.Expr(q"$server.executionContext")
5370
c.Expr[Unit](
5471
q"""
5572
..${macroUtils.imports}
73+
$serverAndClientDefinition
5674
val wasJsonRpcResponse: Boolean = $client.receive($json)
5775
if (!wasJsonRpcResponse) {
5876
$server.receive($json)

shared/src/main/scala/io/github/shogowada/scala/jsonrpc/client/JsonRpcClient.scala

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,15 @@ object JsonRpcClient {
4040
object JsonRpcClientMacro {
4141
def createApi[API: c.WeakTypeTag](c: blackbox.Context): c.Expr[API] = {
4242
import c.universe._
43-
val client: Tree = c.prefix.tree
44-
createApiImpl[c.type, API](c)(client, None)
43+
val macroUtils = JsonRpcMacroUtils[c.type](c)
44+
val (clientDefinition, client) = macroUtils.prefixDefinitionAndReference
45+
val api = createApiImpl[c.type, API](c)(client, None)
46+
c.Expr[API](
47+
q"""
48+
$clientDefinition
49+
$api
50+
"""
51+
)
4552
}
4653

4754
def createApiImpl[CONTEXT <: blackbox.Context, API: c.WeakTypeTag](c: CONTEXT)(
@@ -114,7 +121,7 @@ object JsonRpcClientMacro {
114121

115122
val macroUtils = JsonRpcMacroUtils[c.type](c)
116123

117-
val client = c.prefix.tree
124+
val (clientDefinition, client) = macroUtils.prefixDefinitionAndReference
118125
val jsonSerializer: Tree = q"$client.jsonSerializer"
119126
val promisedResponseRepository: Tree = q"$client.promisedResponseRepository"
120127

@@ -136,6 +143,7 @@ object JsonRpcClientMacro {
136143
c.Expr[Boolean](
137144
q"""
138145
..${macroUtils.imports}
146+
$clientDefinition
139147
$maybePromisedResponse
140148
.map(promisedResponse => {
141149
promisedResponse.success($json)

shared/src/main/scala/io/github/shogowada/scala/jsonrpc/client/JsonRpcMethodClientFactoryMacro.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ class JsonRpcMethodClientFactoryMacro[CONTEXT <: blackbox.Context](val c: CONTEX
9696
jsonRpcFunctionType: Type
9797
): Tree = {
9898
val requestJsonHandlerRepository = macroUtils.getRequestJsonHandlerRepository(server)
99-
10099
val jsonRpcFunctionMethodNameRepository = macroUtils.getJsonRpcFunctionMethodNameRepository(client)
101100

102101
val disposeFunctionMethodHandler = requestJsonHandlerFactoryMacro.createDisposeFunctionMethodHandler(server, client)

shared/src/main/scala/io/github/shogowada/scala/jsonrpc/server/JsonRpcServer.scala

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,16 @@ object JsonRpcServer {
3232

3333
object JsonRpcServerMacro {
3434
def bindApi[API: c.WeakTypeTag](c: blackbox.Context)(api: c.Expr[API]): c.Expr[Unit] = {
35-
bindApiImpl[c.type, API](c)(c.prefix.tree, None, api)
35+
import c.universe._
36+
val macroUtils = JsonRpcMacroUtils[c.type](c)
37+
val (serverDefinition, server) = macroUtils.prefixDefinitionAndReference
38+
val bind = bindApiImpl[c.type, API](c)(server, None, api)
39+
c.Expr[Unit](
40+
q"""
41+
$serverDefinition
42+
$bind
43+
"""
44+
)
3645
}
3746

3847
def bindApiImpl[CONTEXT <: blackbox.Context, API: c.WeakTypeTag](c: CONTEXT)(
@@ -81,10 +90,10 @@ object JsonRpcServerMacro {
8190

8291
val macroUtils = JsonRpcMacroUtils[c.type](c)
8392

84-
val server = c.prefix.tree
85-
val jsonSerializer: Tree = q"$server.jsonSerializer"
93+
val (serverDefinition, server) = macroUtils.prefixDefinitionAndReference
94+
val jsonSerializer: Tree = macroUtils.getJsonSerializer(server)
8695
val requestJsonHandlerRepository = macroUtils.getRequestJsonHandlerRepository(server)
87-
val executionContext: Tree = q"$server.executionContext"
96+
val executionContext: Tree = macroUtils.getExecutionContext(server)
8897

8998
val maybeParseErrorJson: c.Expr[Option[String]] =
9099
macroUtils.createMaybeErrorJson(server, json, c.Expr[JsonRpcError[String]](q"JsonRpcErrors.parseError"))
@@ -129,6 +138,7 @@ object JsonRpcServerMacro {
129138
c.Expr(
130139
q"""
131140
..${macroUtils.imports}
141+
$serverDefinition
132142
$futureMaybeJson
133143
"""
134144
)

shared/src/main/scala/io/github/shogowada/scala/jsonrpc/utils/JsonRpcMacroUtils.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,22 @@ class JsonRpcMacroUtils[CONTEXT <: blackbox.Context](val c: CONTEXT) {
3838

3939
def getExecutionContext(prefix: Tree): Tree = q"$prefix.executionContext"
4040

41+
def prefixDefinitionAndReference: (Tree, Tree) = {
42+
// We do this instead of using c.prefix.tree directly to make sure the reference
43+
// used at the point of macro expansion will always be used for the macro.
44+
// For example, if you have the following code
45+
//
46+
// server.bindApi[Api]
47+
// server = null
48+
//
49+
// then the API bound will break because its c.prefix.tree is now changed to null.
50+
val prefixTermName = TermName(c.freshName())
51+
(
52+
q"val $prefixTermName = ${c.prefix.tree}",
53+
q"$prefixTermName"
54+
)
55+
}
56+
4157
def getJsonRpcApiMethods(apiType: Type): Iterable[MethodSymbol] = {
4258
apiType.decls
4359
.filter((apiMember: Symbol) => isJsonRpcMethod(apiMember))

shared/src/test/scala/io/github/shogowada/scala/jsonrpc/JsonRpcServerAndClientTest.scala

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ class JsonRpcServerAndClientTest extends AsyncFunSpec
2727
val client1 = JsonRpcClient(jsonSerializer, (json: String) => server2.receive(json))
2828
val client2 = JsonRpcClient(jsonSerializer, (json: String) => server1.receive(json))
2929

30-
val serverAndClient1 = JsonRpcServerAndClient(server1, client1)
31-
val serverAndClient2 = JsonRpcServerAndClient(server2, client2)
30+
var serverAndClient1 = JsonRpcServerAndClient(server1, client1)
31+
var serverAndClient2 = JsonRpcServerAndClient(server2, client2)
3232
}
3333

3434
describe("and I have an API that takes function as parameter") {
@@ -210,7 +210,7 @@ class JsonRpcServerAndClientTest extends AsyncFunSpec
210210
client.foo2(() => {})
211211
}
212212

213-
it("then it should use differeht function references on the server too") {
213+
it("then it should use different function references on the server too") {
214214
val fixture = new CallThemBothWithDifferentFunctions
215215
for {
216216
foo1Function <- fixture.promisedFoo1Function.future
@@ -219,5 +219,31 @@ class JsonRpcServerAndClientTest extends AsyncFunSpec
219219
}
220220
}
221221
}
222+
223+
describe("and I changed the reference to servers and clients") {
224+
class IChangedTheReference extends TwoServersAndClients {
225+
226+
trait Api {
227+
def foo(): Future[String]
228+
}
229+
230+
class ApiImpl extends Api {
231+
override def foo(): Future[String] = {
232+
Future("foo")
233+
}
234+
}
235+
236+
serverAndClient1.bindApi[Api](new ApiImpl)
237+
val api = serverAndClient2.createApi[Api]
238+
239+
serverAndClient1 = null
240+
serverAndClient2 = null
241+
}
242+
243+
it("but the APIs should still work") {
244+
val fixture = new IChangedTheReference
245+
fixture.api.foo().map(result => result should equal("foo"))
246+
}
247+
}
222248
}
223249
}

0 commit comments

Comments
 (0)