This is an automated email from the ASF dual-hosted git repository.
He-Pin pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/pekko-grpc.git
The following commit(s) were added to refs/heads/main by this push:
new 09f3cebd feat: add Scala next cross-build coverage (#779)
09f3cebd is described below
commit 09f3cebdb1bc4b73b8a7461722a24c439259f10b
Author: He-Pin(kerr) <[email protected]>
AuthorDate: Mon Jul 6 05:25:02 2026 +0800
feat: add Scala next cross-build coverage (#779)
Motivation:\nPrepare the build for the next Scala 3 LTS lane while keeping
published Scala artifacts on the current 2.13.x and 3.3.x release
lines.\n\nModification:\nCentralize the next Scala version lookup for CI, keep
published crossScalaVersions on release lanes, force the next lane only in
build/test matrices, and fix Scala 3.8.4 compile, MiMa, and formatting
issues.\n\nResult:\n2.13.x, 3.3.8, and 3.8.4 build/test coverage can run while
MiMa and publishing remain on published Scal [...]
---
.github/scripts/resolve-scala-version.sh | 51 +++++
.github/workflows/build-test.yml | 18 +-
.github/workflows/publish-nightly.yml | 9 +-
.github/workflows/stage-release-candidate.yml | 9 +-
.../scala/org/apache/pekko/grpc/BenchRunner.scala | 2 +-
build.sbt | 46 ++++-
.../scala/org/apache/pekko/grpc/gen/Main.scala | 73 ++++---
.../pekko/grpc/interop/GrpcInteropTests.scala | 4 +-
.../pekko/grpc/interop/GrpcInteropSpec.scala | 6 +-
.../interop/PekkoHttpServerProviderScala.scala | 27 ++-
.../grpc/interop/app/PekkoHttpServerAppScala.scala | 8 +-
.../scaladsl/NonBalancingIntegrationSpec.scala | 2 +-
.../apache/pekko/grpc/scaladsl/PowerApiSpec.scala | 2 +-
.../scaladsl/tools/MutableServiceDiscovery.scala | 2 +-
.../myapp/helloworld/ErrorReportingSpec.scala | 7 +-
.../myapp/helloworld/GreeterServiceSpec.scala | 15 +-
project/Common.scala | 22 +-
project/Dependencies.scala | 5 +-
project/ReflectiveCodeGen.scala | 224 +++++++++++++++++++--
project/SbtMavenPlugin.scala | 2 +-
project/VersionGenerator.scala | 2 +-
.../apache/pekko/grpc/internal/TelemetrySpi.scala | 1 +
.../pekko/grpc/javadsl/ServerReflection.scala | 3 +-
.../apache/pekko/grpc/javadsl/ServiceHandler.scala | 4 +-
.../org/apache/pekko/grpc/javadsl/WebHandler.scala | 2 +-
.../org/apache/pekko/grpc/scaladsl/Grpc.scala | 3 +-
.../pekko/grpc/scaladsl/ServiceHandler.scala | 2 +-
.../apache/pekko/grpc/scaladsl/WebHandler.scala | 2 +-
.../pekko/grpc/scaladsl/headers/headers.scala | 5 +
.../internal/PekkoDiscoveryNameResolverSpec.scala | 3 +-
.../pekko/grpc/sbt/PackageMappingCompat.scala | 34 ++++
.../pekko/grpc/sbt/PackageMappingCompat.scala | 31 +++
.../apache/pekko/grpc/sbt/PekkoGrpcPlugin.scala | 31 ++-
.../src/main/scala/example/myapp/Main.scala | 18 +-
.../main/scala/example/myapp/helloworld/Main.scala | 86 ++++----
.../src/main/scala/example/myapp/Main.scala | 18 +-
.../scala3/01-basic-client-server/build.sbt | 10 +-
.../sbt-test/scala3/02-scala3-sourcegen/build.sbt | 8 +-
.../src/sbt-test/scala3/03-sbt2-basic/build.sbt | 12 +-
.../scala/org/apache/pekko/grpc/scalapb/Main.scala | 30 +--
40 files changed, 633 insertions(+), 206 deletions(-)
diff --git a/.github/scripts/resolve-scala-version.sh
b/.github/scripts/resolve-scala-version.sh
new file mode 100644
index 00000000..d2846cd3
--- /dev/null
+++ b/.github/scripts/resolve-scala-version.sh
@@ -0,0 +1,51 @@
+#!/usr/bin/env bash
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+
+set -euo pipefail
+
+scala_version="${1:?scala version is required}"
+repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
+
+resolve_from_build() {
+ local pattern="$1"
+ local resolved
+ resolved="$(sed -n "$pattern" "$repo_root/project/Dependencies.scala")"
+ if [ -z "$resolved" ]; then
+ echo "Unable to resolve Scala version '$scala_version' from
project/Dependencies.scala" >&2
+ exit 1
+ fi
+ printf '%s\n' "$resolved"
+}
+
+case "$scala_version" in
+ scala212)
+ resolve_from_build 's/.*val scala212 = "\(.*\)".*/\1/p'
+ ;;
+ 2.13 | 2.13.x | scala213)
+ resolve_from_build 's/.*val scala213 = "\(.*\)".*/\1/p'
+ ;;
+ 3.3 | 3.3.x | scala3)
+ resolve_from_build 's/.*val scala3 = "\(.*\)".*/\1/p'
+ ;;
+ next)
+ resolve_from_build 's/.*val scala3Next = "\(.*\)".*/\1/p'
+ ;;
+ *)
+ printf '%s\n' "$scala_version"
+ ;;
+esac
diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml
index eb477de3..8466c409 100644
--- a/.github/workflows/build-test.yml
+++ b/.github/workflows/build-test.yml
@@ -85,7 +85,7 @@ jobs:
strategy:
fail-fast: false
matrix:
- SCALA_VERSION: [2.13.18, 3.3.8]
+ SCALA_VERSION: [scala213, scala3, next]
JAVA_VERSION: [17, 21]
steps:
- name: Checkout
@@ -107,9 +107,10 @@ jobs:
- name: Compile and test for JDK ${{ matrix.JAVA_VERSION }}, Scala ${{
matrix.SCALA_VERSION }}
run: |-
+ scala_version="$(bash .github/scripts/resolve-scala-version.sh "${{
matrix.SCALA_VERSION }}")"
cp .jvmopts-ci .jvmopts
- sbt ++${{ matrix.SCALA_VERSION }} test
- sbt ++${{ matrix.SCALA_VERSION }}! codegen/test
+ sbt "++${scala_version}!" test
+ sbt "++${scala_version}!" codegen/test
test-sbt:
name: sbt scripted tests
@@ -121,7 +122,7 @@ jobs:
- test-set: gen-scala-server
scala-version: 2.13
- test-set: scala3
- scala-version: 3.3
+ scala-version: next
- test-set: gen-java
scala-version: 2.13
steps:
@@ -151,7 +152,14 @@ jobs:
uses: coursier/cache-action@95e5b1029b6b86e7bac033ee44a0697d8a527d2d #
v8.1.1
- name: Scripted ${{ matrix.test-set }}
- run: cp .jvmopts-ci .jvmopts && sbt ++${{ matrix.scala-version }}.*
"sbt-plugin/scripted ${{ matrix.test-set }}/*"
+ run: |-
+ cp .jvmopts-ci .jvmopts
+ if [ "${{ matrix.scala-version }}" = "next" ]; then
+ scala_version="$(bash .github/scripts/resolve-scala-version.sh
"${{ matrix.scala-version }}")"
+ sbt "++${scala_version}!" "sbt-plugin/scripted ${{ matrix.test-set
}}/*"
+ else
+ sbt "++${{ matrix.scala-version }}.*" "sbt-plugin/scripted ${{
matrix.test-set }}/*"
+ fi
test-gradle:
name: Gradle tests
diff --git a/.github/workflows/publish-nightly.yml
b/.github/workflows/publish-nightly.yml
index b17119ca..08a8c210 100644
--- a/.github/workflows/publish-nightly.yml
+++ b/.github/workflows/publish-nightly.yml
@@ -36,11 +36,14 @@ jobs:
- name: Publish
run: |-
+ scala_212="$(bash .github/scripts/resolve-scala-version.sh scala212)"
+ scala_213="$(bash .github/scripts/resolve-scala-version.sh scala213)"
+ scala_3="$(bash .github/scripts/resolve-scala-version.sh scala3)"
cp .jvmopts-ci .jvmopts
sbt +publish
- sbt ++2.12.21! maven-plugin/publish
- sbt ++2.13.18! codegen/publish
- sbt ++3.3.8! codegen/publish
+ sbt "++${scala_212}!" maven-plugin/publish
+ sbt "++${scala_213}!" codegen/publish
+ sbt "++${scala_3}!" codegen/publish
env:
NEXUS_USER: ${{ secrets.NEXUS_USER }}
NEXUS_PW: ${{ secrets.NEXUS_PW }}
diff --git a/.github/workflows/stage-release-candidate.yml
b/.github/workflows/stage-release-candidate.yml
index 102aded3..ca4bd3ea 100644
--- a/.github/workflows/stage-release-candidate.yml
+++ b/.github/workflows/stage-release-candidate.yml
@@ -226,12 +226,15 @@ jobs:
- name: Build, sign and stage artifacts
run: |-
VERSION=$(echo $REF | sed -e "s/.\(.*\)-.*/\\1/")
+ scala_212="$(bash .github/scripts/resolve-scala-version.sh scala212)"
+ scala_213="$(bash .github/scripts/resolve-scala-version.sh scala213)"
+ scala_3="$(bash .github/scripts/resolve-scala-version.sh scala3)"
echo "$PEKKO_GPG_SECRET_KEY" | gpg --batch --import --import-options
import-show
sbt "set ThisBuild / version := \"$VERSION\"; +publishSigned"
- sbt "set ThisBuild / version := \"$VERSION\"; ++2.12.21!
maven-plugin/publishSigned"
- sbt "set ThisBuild / version := \"$VERSION\"; ++2.13.18!
codegen/publishSigned"
- sbt "set ThisBuild / version := \"$VERSION\"; ++3.3.8!
codegen/publishSigned"
+ sbt "set ThisBuild / version := \"$VERSION\"; ++${scala_212}!
maven-plugin/publishSigned"
+ sbt "set ThisBuild / version := \"$VERSION\"; ++${scala_213}!
codegen/publishSigned"
+ sbt "set ThisBuild / version := \"$VERSION\"; ++${scala_3}!
codegen/publishSigned"
sbt "set ThisBuild / version := \"$VERSION\"; sonatypePrepare; set
ThisBuild / version := \"$VERSION\"; sonatypeBundleUpload; sonatypeClose"
env:
REF: ${{ github.ref_name }}
diff --git a/benchmarks/src/main/scala/org/apache/pekko/grpc/BenchRunner.scala
b/benchmarks/src/main/scala/org/apache/pekko/grpc/BenchRunner.scala
index 58d6c5d2..76f0272d 100644
--- a/benchmarks/src/main/scala/org/apache/pekko/grpc/BenchRunner.scala
+++ b/benchmarks/src/main/scala/org/apache/pekko/grpc/BenchRunner.scala
@@ -31,7 +31,7 @@ object BenchRunner {
}
// @formatter:on
- val opts = new CommandLineOptions(args2: _*)
+ val opts = new CommandLineOptions(args2 *)
val results = new Runner(opts).run()
val report = results.asScala.map { (result: RunResult) =>
diff --git a/build.sbt b/build.sbt
index af477539..eba8a843 100644
--- a/build.sbt
+++ b/build.sbt
@@ -116,7 +116,12 @@ lazy val runtime = Project(id = "runtime", base =
file("runtime"))
ReflectiveCodeGen.generatedLanguages := Seq("Scala"),
ReflectiveCodeGen.extraGenerators := Seq("ScalaMarshallersCodeGenerator"),
PB.protocVersion := Dependencies.Versions.googleProtoc,
- Test / PB.targets += (scalapb.gen() -> (Test / sourceManaged).value))
+ Test / PB.targets += {
+ val scalapbGenerator =
+ if (scalaBinaryVersion.value == "3")
scalapb.gen(scalapb.GeneratorOption.Scala3Sources)
+ else scalapb.gen()
+ scalapbGenerator -> (Test / sourceManaged).value
+ })
.enablePlugins(org.apache.pekko.grpc.build.ReflectiveCodeGen)
.enablePlugins(ReproducibleBuildsPlugin)
@@ -162,6 +167,7 @@ lazy val mavenPlugin = Project(id = "maven-plugin", base =
file("maven-plugin"))
.settings(
name := s"$pekkoPrefix-maven-plugin",
crossPaths := false,
+ crossTarget := target.value / s"scala-${scalaVersion.value}",
crossScalaVersions := Dependencies.Versions.CrossScalaForPlugin,
scalaVersion := Dependencies.Versions.CrossScalaForPlugin.head)
.dependsOn(codegen)
@@ -173,15 +179,21 @@ lazy val sbtPlugin = Project(id = "sbt-plugin", base =
file("sbt-plugin"))
.settings(Dependencies.sbtPlugin)
.settings(
name := s"$pekkoPrefix-sbt-plugin",
+ sbt.Keys.sbtPlugin :=
+
Dependencies.Versions.CrossScalaForSbtPlugin.contains(scalaVersion.value),
pluginCrossBuild / sbtVersion := {
- scalaBinaryVersion.value match {
- case "2.12" => "1.12.13"
- case _ => "2.0.0"
+ if
(!Dependencies.Versions.CrossScalaForSbtPlugin.contains(scalaVersion.value))
"1.12.13"
+ else {
+ scalaBinaryVersion.value match {
+ case "2.12" => "1.12.13"
+ case _ => "2.0.0"
+ }
}
},
/** And for scripted tests: */
scriptedSbt := (pluginCrossBuild / sbtVersion).value,
scriptedLaunchOpts += ("-Dproject.version=" + version.value),
+ scriptedLaunchOpts += ("-Dpekko.grpc.scala3.next.version=" +
Dependencies.Versions.scala3Next),
scriptedLaunchOpts ++= sys.props.collect { case (k @ "sbt.ivy.home", v) =>
s"-D$k=$v" }.toSeq,
scriptedDependencies := {
val p1 = publishLocal.value
@@ -195,10 +207,25 @@ lazy val sbtPlugin = Project(id = "sbt-plugin", base =
file("sbt-plugin"))
case "2.12" => Seq("-Xsource:3")
case _ => Seq.empty
}
+ },
+ libraryDependencies := {
+ val dependencies = libraryDependencies.value
+ if
(Dependencies.Versions.CrossScalaForSbtPlugin.contains(scalaVersion.value))
dependencies
+ else Seq.empty
+ },
+ Compile / sources := {
+ val sources0 = (Compile / sources).value
+ if
(Dependencies.Versions.CrossScalaForSbtPlugin.contains(scalaVersion.value))
sources0
+ else Seq.empty
+ },
+ Test / sources := {
+ val sources0 = (Test / sources).value
+ if
(Dependencies.Versions.CrossScalaForSbtPlugin.contains(scalaVersion.value))
sources0
+ else Seq.empty
})
.settings(
- crossScalaVersions := Dependencies.Versions.CrossScalaForPlugin,
- scalaVersion := Dependencies.Versions.CrossScalaForPlugin.head)
+ crossScalaVersions := Dependencies.Versions.CrossScalaForSbtPlugin,
+ scalaVersion := Dependencies.Versions.CrossScalaForSbtPlugin.head)
.dependsOn(codegen)
lazy val interopTests = Project(id = "interop-tests", base =
file("interop-tests"))
@@ -220,8 +247,11 @@ lazy val interopTests = Project(id = "interop-tests", base
= file("interop-tests
ReflectiveCodeGen.generatedLanguages := Seq("Scala", "Java"),
ReflectiveCodeGen.extraGenerators := Seq("ScalaMarshallersCodeGenerator"),
ReflectiveCodeGen.codeGeneratorSettings ++= Seq("server_power_apis"),
- // grpc 1.54.2 brings in extra unnecessary proto files that cause build
issues
- PB.generate / excludeFilter := new SimpleFileFilter(f =>
f.getAbsolutePath().contains("envoy")),
+ // grpc brings in extra unnecessary proto files that cause build issues or
generated-code warnings
+ PB.generate / excludeFilter := new SimpleFileFilter(f => {
+ val path = f.getAbsolutePath.replace('\\', '/')
+ path.contains("envoy") || path.contains("grpc/reflection/v1alpha")
+ }),
PB.protocVersion := Dependencies.Versions.googleProtoc,
// We need to be able to publish locally in order for sbt interopt tests
to work
// however this sbt project should not be published to an actual repository
diff --git a/codegen/src/main/scala/org/apache/pekko/grpc/gen/Main.scala
b/codegen/src/main/scala/org/apache/pekko/grpc/gen/Main.scala
index b50d4648..9b7ad4d6 100644
--- a/codegen/src/main/scala/org/apache/pekko/grpc/gen/Main.scala
+++ b/codegen/src/main/scala/org/apache/pekko/grpc/gen/Main.scala
@@ -16,59 +16,56 @@ package org.apache.pekko.grpc.gen
import java.io.ByteArrayOutputStream
import java.net.URLDecoder
-import scala.annotation.nowarn
-
import com.google.protobuf.compiler.PluginProtos.CodeGeneratorRequest
import org.apache.pekko
import pekko.grpc.gen.javadsl.{ JavaClientCodeGenerator,
JavaInterfaceCodeGenerator, JavaServerCodeGenerator }
import pekko.grpc.gen.scaladsl.{ ScalaClientCodeGenerator,
ScalaServerCodeGenerator, ScalaTraitCodeGenerator }
// This is the protoc plugin that the gradle plugin uses
-@nowarn("msg=deprecated")
-object Main extends App {
- val inBytes: Array[Byte] = {
- val baos = new ByteArrayOutputStream(math.max(64, System.in.available()))
- val buffer = new Array[Byte](32 * 1024)
+object Main {
+ def main(args: Array[String]): Unit = {
+ val inBytes: Array[Byte] = {
+ val baos = new ByteArrayOutputStream(math.max(64, System.in.available()))
+ val buffer = new Array[Byte](32 * 1024)
- var bytesRead = System.in.read(buffer)
- while (bytesRead >= 0) {
- baos.write(buffer, 0, bytesRead)
- bytesRead = System.in.read(buffer)
+ var bytesRead = System.in.read(buffer)
+ while (bytesRead >= 0) {
+ baos.write(buffer, 0, bytesRead)
+ bytesRead = System.in.read(buffer)
+ }
+ baos.toByteArray
}
- baos.toByteArray
- }
- val req = CodeGeneratorRequest.parseFrom(inBytes)
- val KeyValueRegex = """([^=]+)=(.*)""".r
- val parameters = req.getParameter
- .split(",")
- .flatMap {
- case KeyValueRegex(key, value) => Some((key.toLowerCase, value))
- case _ => None
- }
- .toMap
+ val req = CodeGeneratorRequest.parseFrom(inBytes)
+ val KeyValueRegex = """([^=]+)=(.*)""".r
+ val parameters = req.getParameter
+ .split(",")
+ .flatMap {
+ case KeyValueRegex(key, value) => Some((key.toLowerCase, value))
+ case _ => None
+ }
+ .toMap
- private val languageScala: Boolean =
parameters.get("language").map(_.equalsIgnoreCase("scala")).getOrElse(false)
+ val languageScala: Boolean =
parameters.get("language").map(_.equalsIgnoreCase("scala")).getOrElse(false)
- private val generateClient: Boolean =
-
parameters.get("generate_client").map(!_.equalsIgnoreCase("false")).getOrElse(true)
+ val generateClient: Boolean =
+
parameters.get("generate_client").map(!_.equalsIgnoreCase("false")).getOrElse(true)
- private val generateServer: Boolean =
-
parameters.get("generate_server").map(!_.equalsIgnoreCase("false")).getOrElse(true)
+ val generateServer: Boolean =
+
parameters.get("generate_server").map(!_.equalsIgnoreCase("false")).getOrElse(true)
- private val extraGenerators: List[String] =
- parameters.getOrElse("extra_generators", "").split(";").toList.filter(_ !=
"")
+ val extraGenerators: List[String] =
+ parameters.getOrElse("extra_generators", "").split(";").toList.filter(_
!= "")
- // Prefer logfile_enc with fallback to logfile
- private val logger: Logger =
- parameters
- .get("logfile_enc")
- .map(URLDecoder.decode(_, "utf-8"))
- .orElse(parameters.get("logfile"))
- .map(new FileLogger(_))
- .getOrElse(SilencedLogger)
+ // Prefer logfile_enc with fallback to logfile
+ val logger: Logger =
+ parameters
+ .get("logfile_enc")
+ .map(URLDecoder.decode(_, "utf-8"))
+ .orElse(parameters.get("logfile"))
+ .map(new FileLogger(_))
+ .getOrElse(SilencedLogger)
- val out = {
val codeGenerators =
if (languageScala) {
// Scala
diff --git
a/interop-tests/src/main/scala/org/apache/pekko/grpc/interop/GrpcInteropTests.scala
b/interop-tests/src/main/scala/org/apache/pekko/grpc/interop/GrpcInteropTests.scala
index 45764504..7c29e77a 100644
---
a/interop-tests/src/main/scala/org/apache/pekko/grpc/interop/GrpcInteropTests.scala
+++
b/interop-tests/src/main/scala/org/apache/pekko/grpc/interop/GrpcInteropTests.scala
@@ -139,7 +139,7 @@ object IoGrpcJavaServerProvider extends GrpcServerProvider {
val pendingCases =
Set()
- val server = IoGrpcServer
+ val server: GrpcServer[?] = IoGrpcServer
}
object IoGrpcJavaClientProvider extends GrpcClientProvider {
@@ -148,7 +148,7 @@ object IoGrpcJavaClientProvider extends GrpcClientProvider {
val pendingCases =
Set()
- val client = IoGrpcClient
+ val client: GrpcClient = IoGrpcClient
}
trait PekkoHttpServerProvider extends GrpcServerProvider
diff --git
a/interop-tests/src/test/scala/org/apache/pekko/grpc/interop/GrpcInteropSpec.scala
b/interop-tests/src/test/scala/org/apache/pekko/grpc/interop/GrpcInteropSpec.scala
index 577f1252..a9299c2d 100644
---
a/interop-tests/src/test/scala/org/apache/pekko/grpc/interop/GrpcInteropSpec.scala
+++
b/interop-tests/src/test/scala/org/apache/pekko/grpc/interop/GrpcInteropSpec.scala
@@ -79,7 +79,7 @@ object PekkoHttpServerProviderJava$ extends
PekkoHttpServerProvider {
val pendingCases =
Set("custom_metadata")
- val server = new PekkoGrpcServerJava((mat, sys) => {
+ val server: GrpcServer[?] = new PekkoGrpcServerJava((mat, sys) => {
TestServiceHandlerFactory.create(new JavaTestServiceImpl(mat), sys)
})
}
@@ -87,13 +87,13 @@ object PekkoHttpServerProviderJava$ extends
PekkoHttpServerProvider {
class PekkoClientProviderScala(backend: String, testWithSslContext: Boolean)
extends PekkoClientProvider {
val label: String = s"pekko-grpc scala client tester $backend"
- def client = PekkoGrpcClientScala(settings =>
+ def client: GrpcClient = PekkoGrpcClientScala(settings =>
implicit sys => new PekkoGrpcScalaClientTester(settings, backend,
testWithSslContext))
}
class PekkoClientProviderJava(backend: String, testWithSslContext: Boolean)
extends PekkoClientProvider {
val label: String = "pekko-grpc java client tester"
- def client = new PekkoGrpcClientJava((settings, sys) =>
+ def client: GrpcClient = new PekkoGrpcClientJava((settings, sys) =>
new PekkoGrpcJavaClientTester(settings, sys, backend, testWithSslContext))
}
diff --git
a/interop-tests/src/test/scala/org/apache/pekko/grpc/interop/PekkoHttpServerProviderScala.scala
b/interop-tests/src/test/scala/org/apache/pekko/grpc/interop/PekkoHttpServerProviderScala.scala
index 64ef1966..a7b9db38 100644
---
a/interop-tests/src/test/scala/org/apache/pekko/grpc/interop/PekkoHttpServerProviderScala.scala
+++
b/interop-tests/src/test/scala/org/apache/pekko/grpc/interop/PekkoHttpServerProviderScala.scala
@@ -16,15 +16,22 @@ package org.apache.pekko.grpc.interop
import org.apache.pekko
import pekko.NotUsed
import pekko.actor.ActorSystem
-import pekko.grpc.GrpcProtocol
+import pekko.grpc.{ GrpcProtocol, ProtobufSerializer }
import pekko.grpc.internal.{ GrpcEntityHelpers, GrpcProtocolNative,
GrpcResponseHelpers, Identity }
+import pekko.http.scaladsl.marshalling.ToResponseMarshaller
import pekko.http.scaladsl.model.headers.RawHeader
import pekko.http.scaladsl.model.{ AttributeKeys, HttpEntity, HttpHeader,
Trailer }
import pekko.http.scaladsl.server.{ Directive0, Directives, Route }
+import pekko.http.scaladsl.unmarshalling.FromRequestUnmarshaller
import pekko.stream.Materializer
import pekko.stream.scaladsl.Source
import io.grpc.Status
-import io.grpc.testing.integration.messages.{ SimpleRequest,
StreamingOutputCallRequest }
+import io.grpc.testing.integration.messages.{
+ SimpleRequest,
+ SimpleResponse,
+ StreamingOutputCallRequest,
+ StreamingOutputCallResponse
+}
import io.grpc.testing.integration.test.{ TestService, TestServiceHandler,
TestServiceMarshallers }
import scala.collection.immutable
@@ -63,7 +70,21 @@ object PekkoHttpServerProviderScala extends
PekkoHttpServerProvider with Directi
implicit val ec: ExecutionContext = mat.executionContext
implicit val writer: GrpcProtocol.GrpcProtocolWriter =
GrpcProtocolNative.newWriter(Identity)
- import TestServiceMarshallers._
+ implicit val simpleRequestSerializer: ProtobufSerializer[SimpleRequest] =
+ TestService.Serializers.SimpleRequestSerializer
+ implicit val simpleResponseSerializer: ProtobufSerializer[SimpleResponse] =
+ TestService.Serializers.SimpleResponseSerializer
+ implicit val streamingOutputCallRequestSerializer:
ProtobufSerializer[StreamingOutputCallRequest] =
+ TestService.Serializers.StreamingOutputCallRequestSerializer
+ implicit val streamingOutputCallResponseSerializer:
ProtobufSerializer[StreamingOutputCallResponse] =
+ TestService.Serializers.StreamingOutputCallResponseSerializer
+ implicit val simpleRequestUnmarshaller:
FromRequestUnmarshaller[SimpleRequest] =
+ TestServiceMarshallers.unmarshaller[SimpleRequest]
+ implicit val streamingOutputCallRequestUnmarshaller
+ : FromRequestUnmarshaller[Source[StreamingOutputCallRequest, NotUsed]]
=
+ TestServiceMarshallers.toSourceUnmarshaller[StreamingOutputCallRequest]
+ implicit val simpleResponseMarshaller:
ToResponseMarshaller[SimpleResponse] =
+ TestServiceMarshallers.marshaller[SimpleResponse]
pathPrefix("UnaryCall") {
entity(as[SimpleRequest]) { req =>
diff --git
a/interop-tests/src/test/scala/org/apache/pekko/grpc/interop/app/PekkoHttpServerAppScala.scala
b/interop-tests/src/test/scala/org/apache/pekko/grpc/interop/app/PekkoHttpServerAppScala.scala
index 0901c698..7f0af18a 100644
---
a/interop-tests/src/test/scala/org/apache/pekko/grpc/interop/app/PekkoHttpServerAppScala.scala
+++
b/interop-tests/src/test/scala/org/apache/pekko/grpc/interop/app/PekkoHttpServerAppScala.scala
@@ -23,7 +23,9 @@ import
org.apache.pekko.grpc.interop.PekkoHttpServerProviderScala
*
* You can start this app from sbt with 'interop-tests/test:reStart'
*/
-object PekkoHttpServerAppScala extends App {
- val (sys, binding) = PekkoHttpServerProviderScala.server.start(Array())
- sys.log.info(s"Bound to ${binding.localAddress}")
+object PekkoHttpServerAppScala {
+ def main(args: Array[String]): Unit = {
+ val (sys, binding) = PekkoHttpServerProviderScala.server.start(Array())
+ sys.log.info(s"Bound to ${binding.localAddress}")
+ }
}
diff --git
a/interop-tests/src/test/scala/org/apache/pekko/grpc/scaladsl/NonBalancingIntegrationSpec.scala
b/interop-tests/src/test/scala/org/apache/pekko/grpc/scaladsl/NonBalancingIntegrationSpec.scala
index 574e726e..1f1cf7bb 100644
---
a/interop-tests/src/test/scala/org/apache/pekko/grpc/scaladsl/NonBalancingIntegrationSpec.scala
+++
b/interop-tests/src/test/scala/org/apache/pekko/grpc/scaladsl/NonBalancingIntegrationSpec.scala
@@ -164,7 +164,7 @@ class NonBalancingIntegrationSpec(backend: String)
"eventually fail when no valid endpoints are provided" in {
// https://github.com/akka/akka-grpc/issues/1246
if (backend == "pekko-http")
- cancel("The Pekko HTTP backend doesn't fail when the persistent
connection fails")
+ pending
val discovery =
new MutableServiceDiscovery(
diff --git
a/interop-tests/src/test/scala/org/apache/pekko/grpc/scaladsl/PowerApiSpec.scala
b/interop-tests/src/test/scala/org/apache/pekko/grpc/scaladsl/PowerApiSpec.scala
index c1560c4a..f2f40a29 100644
---
a/interop-tests/src/test/scala/org/apache/pekko/grpc/scaladsl/PowerApiSpec.scala
+++
b/interop-tests/src/test/scala/org/apache/pekko/grpc/scaladsl/PowerApiSpec.scala
@@ -67,7 +67,7 @@ abstract class PowerApiSpec(backend: String)
val server: Http.ServerBinding =
Http().newServerAt("localhost", 0).bind(GreeterServicePowerApiHandler(new
PowerGreeterServiceImpl())).futureValue
- var client: GreeterServiceClient = _
+ var client: GreeterServiceClient = null
after {
if (client != null && !client.closed.isCompleted) {
diff --git
a/interop-tests/src/test/scala/org/apache/pekko/grpc/scaladsl/tools/MutableServiceDiscovery.scala
b/interop-tests/src/test/scala/org/apache/pekko/grpc/scaladsl/tools/MutableServiceDiscovery.scala
index 1f088de6..97f1a245 100644
---
a/interop-tests/src/test/scala/org/apache/pekko/grpc/scaladsl/tools/MutableServiceDiscovery.scala
+++
b/interop-tests/src/test/scala/org/apache/pekko/grpc/scaladsl/tools/MutableServiceDiscovery.scala
@@ -29,7 +29,7 @@ import scala.concurrent.duration.FiniteDuration
* An In-Memory ServiceDiscovery that only can lookup "greeter"
*/
final class MutableServiceDiscovery(targets: List[InetSocketAddress]) extends
ServiceDiscovery {
- var services: Future[Resolved] = _
+ var services: Future[Resolved] = null
setServices(targets)
diff --git
a/plugin-tester-scala/src/test/scala/example/myapp/helloworld/ErrorReportingSpec.scala
b/plugin-tester-scala/src/test/scala/example/myapp/helloworld/ErrorReportingSpec.scala
index ae43a08d..f1eb708a 100644
---
a/plugin-tester-scala/src/test/scala/example/myapp/helloworld/ErrorReportingSpec.scala
+++
b/plugin-tester-scala/src/test/scala/example/myapp/helloworld/ErrorReportingSpec.scala
@@ -31,6 +31,7 @@ import org.scalatest.time.Span
import org.scalatest.wordspec.AnyWordSpec
import org.scalatestplus.junit.JUnitRunner
+import scala.annotation.nowarn
import scala.concurrent.Await
import scala.concurrent.duration._
@@ -45,7 +46,11 @@ class ErrorReportingSpec extends AnyWordSpec with Matchers
with ScalaFutures wit
val binding = Http()
.newServerAt("127.0.0.1", 0)
- .bind(GreeterServiceHandler(new
GreeterServiceImpl())(system.asInstanceOf[ClassicActorSystemProvider]))
+ .bind {
+ @nowarn("msg=local val .* is never used")
+ implicit val classicSystem: ClassicActorSystemProvider = system
+ GreeterServiceHandler(new GreeterServiceImpl())
+ }
.futureValue
"respond with an 'unimplemented' gRPC error status when calling an unknown
method" in {
diff --git
a/plugin-tester-scala/src/test/scala/example/myapp/helloworld/GreeterServiceSpec.scala
b/plugin-tester-scala/src/test/scala/example/myapp/helloworld/GreeterServiceSpec.scala
index 676bdbc6..3431d459 100644
---
a/plugin-tester-scala/src/test/scala/example/myapp/helloworld/GreeterServiceSpec.scala
+++
b/plugin-tester-scala/src/test/scala/example/myapp/helloworld/GreeterServiceSpec.scala
@@ -27,6 +27,7 @@ import org.scalatest.time.Span
import org.scalatest.wordspec.AnyWordSpecLike
import org.scalatestplus.junit.JUnitRunner
+import scala.annotation.nowarn
import scala.concurrent.{ Await, ExecutionContext }
import scala.concurrent.duration._
@@ -51,11 +52,15 @@ class GreeterServiceSpec extends Matchers with
AnyWordSpecLike with BeforeAndAft
implicit val ec: ExecutionContext = clientSystem.dispatcher
- val clients = Seq(8080, 8081).map { port =>
- GreeterServiceClient(
- GrpcClientSettings
- .connectToServiceAt("127.0.0.1",
port)(clientSystem.asInstanceOf[ClassicActorSystemProvider])
- .withTls(false))(clientSystem.asInstanceOf[ClassicActorSystemProvider])
+ val clients = {
+ @nowarn("msg=local val .* is never used")
+ implicit val classicClientSystem: ClassicActorSystemProvider = clientSystem
+ Seq(8080, 8081).map { port =>
+ GreeterServiceClient(
+ GrpcClientSettings
+ .connectToServiceAt("127.0.0.1", port)
+ .withTls(false))
+ }
}
override def afterAll(): Unit = {
diff --git a/project/Common.scala b/project/Common.scala
index eb9a904c..b0529220 100644
--- a/project/Common.scala
+++ b/project/Common.scala
@@ -27,6 +27,15 @@ object Common extends AutoPlugin {
private val consoleDisabledOptions = Seq("-Xfatal-warnings",
"-Ywarn-unused", "-Ywarn-unused-import")
val isScala3 = Def.setting(scalaBinaryVersion.value == "3")
+ val isScala38OrLater =
Def.setting(CrossVersion.partialVersion(scalaVersion.value).exists {
+ case (3, minor) if minor >= 8 => true
+ case _ => false
+ })
+
+ private val scala38WarningOptions = Seq(
+ "-Wconf:msg=Implicit parameters should be provided with a `using`
clause:silent",
+ "-Wconf:msg=The trailing .* for eta-expansion is unnecessary:silent",
+ "-Wconf:msg=Usage of implicit .* is not accessible here:silent")
override def globalSettings =
Seq(
@@ -52,11 +61,12 @@ object Common extends AutoPlugin {
"-Xfatal-warnings",
"-Ywarn-unused",
"-encoding",
- "UTF-8")
+ "UTF-8") ++
+ (if (scalaVersion.value.startsWith("2.13.")) Seq("-Xsource:3") else
Seq.empty)
else
Seq("-unchecked", "-deprecation", "-Werror", "-Wunused:imports",
"-encoding", "UTF-8") ++
- (if (CrossVersion.partialVersion(scalaVersion.value).exists(_._2 <
9)) Seq("-Yfuture-lazy-vals")
- else Seq.empty)),
+ (if (isScala38OrLater.value) scala38WarningOptions else Seq.empty) ++
+ (if (scalaVersion.value.startsWith("3.3.")) Seq("-Yfuture-lazy-vals")
else Seq.empty)),
Compile / scalacOptions ++=
(if (!isScala3.value)
Seq(
@@ -70,9 +80,15 @@ object Common extends AutoPlugin {
// Generated code for methods/fields marked 'deprecated'
"-Wconf:msg=Marked as deprecated in proto file:silent",
"-Wconf:msg=unused import:silent",
+ "-Wconf:msg=transient key .* is excluded from the cache
input:silent",
"-Wconf:cat=feature:silent")),
Compile / console / scalacOptions ~=
(_.filterNot(consoleDisabledOptions.contains)),
javacOptions ++= List("-Xlint:unchecked", "-Xlint:deprecation"),
+ javacOptions := {
+ val options = javacOptions.value
+ if (isScala38OrLater.value) options.filterNot(_.startsWith("-Xlint")) ++
Seq("-nowarn", "-Xlint:none")
+ else options
+ },
Compile / compile / javacOptions ++= Seq("--release", "17"),
Compile / compile / scalacOptions ++= Seq("-release", "17"),
Test / compile / scalacOptions ++= Seq("-release", "17"),
diff --git a/project/Dependencies.scala b/project/Dependencies.scala
index 832f9a64..b23455c6 100644
--- a/project/Dependencies.scala
+++ b/project/Dependencies.scala
@@ -20,11 +20,12 @@ object Dependencies {
val scala212 = "2.12.21"
val scala213 = "2.13.18"
val scala3 = "3.3.8"
- val scala3_8 = "3.8.4"
+ val scala3Next = "3.8.4"
// the order in the list is important because the head will be considered
the default.
val CrossScalaForLib = Seq(scala213, scala3)
- val CrossScalaForPlugin = Seq(scala212, scala3_8)
+ val CrossScalaForPlugin = Seq(scala212, scala3)
+ val CrossScalaForSbtPlugin = Seq(scala212, scala3Next)
val CrossScalaAll = Seq(scala212, scala213, scala3)
// We don't force Pekko updates because downstream projects can upgrade
diff --git a/project/ReflectiveCodeGen.scala b/project/ReflectiveCodeGen.scala
index ed126bb0..80636113 100644
--- a/project/ReflectiveCodeGen.scala
+++ b/project/ReflectiveCodeGen.scala
@@ -10,6 +10,8 @@
package org.apache.pekko.grpc.build
import java.io.File
+import java.lang.invoke.{ MethodHandles, MethodType }
+import java.net.{ URL, URLClassLoader }
import sbt._
import sbt.Keys._
import sbtprotoc.ProtocPlugin
@@ -24,16 +26,21 @@ import protocbridge.{ Artifact => BridgeArtifact }
/** A plugin that allows to use a code generator compiled in one subproject to
be used in a test project */
object ReflectiveCodeGen extends AutoPlugin {
- lazy val generatedLanguages =
SettingKey[Seq[String]]("reflectiveGrpcGeneratedLanguages")
- lazy val generatedSources =
SettingKey[Seq[String]]("reflectiveGrpcGeneratedSources")
- lazy val extraGenerators =
SettingKey[Seq[String]]("reflectiveGrpcExtraGenerators")
- lazy val codeGeneratorSettings = settingKey[Seq[String]]("Code generator
settings")
- lazy val protocOptions = settingKey[Seq[String]]("Protoc Options.")
+ lazy val generatedLanguages =
+ SettingKey[Seq[String]]("reflectiveGrpcGeneratedLanguages", "Generated
languages").withRank(KeyRanks.Invisible)
+ lazy val generatedSources =
+ SettingKey[Seq[String]]("reflectiveGrpcGeneratedSources", "Generated
sources").withRank(KeyRanks.Invisible)
+ lazy val extraGenerators =
+ SettingKey[Seq[String]]("reflectiveGrpcExtraGenerators", "Extra code
generators").withRank(KeyRanks.Invisible)
+ lazy val codeGeneratorSettings =
+ SettingKey[Seq[String]]("codeGeneratorSettings", "Code generator
settings").withRank(KeyRanks.Invisible)
+ lazy val protocOptions =
+ SettingKey[Seq[String]]("protocOptions", "Protoc
options.").withRank(KeyRanks.Invisible)
// needed to be able to override the PB.generate task reliably
override lazy val requires = ProtocPlugin
- override lazy val projectSettings: Seq[Def.Setting[?]] =
+ override lazy val projectSettings =
inConfig(Compile)(
Seq(
PB.protocOptions := protocOptions.value,
@@ -72,16 +79,27 @@ object ReflectiveCodeGen extends AutoPlugin {
}
}
}.value,
- setCodeGenerator := loadAndSetGenerator(
- // the magic sauce: use the output classpath from the the sbt-plugin
project and instantiate generators from there
- (ProjectRef(file("."), "sbt-plugin") / Compile /
fullClasspath).value,
- generatedLanguages.value,
- generatedSources.value,
- extraGenerators.value,
- sourceManaged.value,
- codeGeneratorSettings.value,
- PB.targets.value.asInstanceOf[ListBuffer[Target]],
- scalaBinaryVersion.value),
+ setCodeGenerator := Def.taskDyn {
+ // Scala 2.12 still uses the sbt-plugin/toolbox path. Library cross
builds use codegen
+ // directly so forced 2.13/3.3 matrix runs do not compile the sbt 2
plugin project.
+ val generatorProject =
+ if (scalaBinaryVersion.value == "2.12") "sbt-plugin"
+ else "codegen"
+
+ Def.task {
+ loadAndSetGenerator(
+ (ProjectRef(file("."), generatorProject) / Compile /
fullClasspath).value,
+ generatedLanguages.value,
+ generatedSources.value,
+ extraGenerators.value,
+ sourceManaged.value,
+ codeGeneratorSettings.value ++ {
+ if (scalaBinaryVersion.value == "3") Seq("scala3_sources")
else Seq.empty
+ },
+ PB.targets.value.asInstanceOf[ListBuffer[Target]],
+ scalaBinaryVersion.value)
+ }
+ }.value,
(Compile / PB.protoSources) := PB.protoSources.value ++ Seq(
PB.externalIncludePath.value,
sourceDirectory.value / "proto"))) ++ Seq(
@@ -104,6 +122,19 @@ object ReflectiveCodeGen extends AutoPlugin {
generatorSettings: Seq[String],
targets: ListBuffer[Target],
scalaBinaryVersion: String): Unit = {
+ if (scalaBinaryVersion != "2.12") {
+ loadAndSetGeneratorWithMethodHandles(
+ classpath,
+ languages0,
+ sources0,
+ extraGenerators0,
+ targetPath,
+ generatorSettings,
+ targets,
+ scalaBinaryVersion)
+ return
+ }
+
val languages = languages0.mkString(", ")
val sources = sources0.mkString(", ")
val extraGenerators = extraGenerators0.mkString(", ")
@@ -146,6 +177,167 @@ object ReflectiveCodeGen extends AutoPlugin {
targets ++= generators.asInstanceOf[Seq[Target]]
}
+ private def loadAndSetGeneratorWithMethodHandles(
+ classpath: Classpath,
+ languages0: Seq[String],
+ sources0: Seq[String],
+ extraGenerators0: Seq[String],
+ targetPath: File,
+ generatorSettings: Seq[String],
+ targets: ListBuffer[Target],
+ scalaBinaryVersion: String): Unit = {
+ val generatorClasspath = classpath.map(_.data)
+ val codegenArtifact =
+ BridgeArtifact("org.apache.pekko",
s"pekko-grpc-codegen_$scalaBinaryVersion", "0.0.0")
+
+ final case class GeneratorDefinition(name: String, className: String,
suggestedDependencies: Seq[BridgeArtifact])
+
+ def codeGenerator(name: String): GeneratorDefinition = {
+ name match {
+ case "ScalaTraitCodeGenerator" =>
+ GeneratorDefinition(
+ "pekko-grpc-scaladsl-trait",
+ "org.apache.pekko.grpc.gen.scaladsl.ScalaTraitCodeGenerator$",
+ Seq.empty)
+ case "ScalaClientCodeGenerator" =>
+ GeneratorDefinition(
+ "pekko-grpc-scaladsl-client",
+ "org.apache.pekko.grpc.gen.scaladsl.ScalaClientCodeGenerator$",
+ Seq.empty)
+ case "ScalaServerCodeGenerator" =>
+ GeneratorDefinition(
+ "pekko-grpc-scaladsl-server",
+ "org.apache.pekko.grpc.gen.scaladsl.ScalaServerCodeGenerator$",
+ Seq.empty)
+ case "ScalaMarshallersCodeGenerator" =>
+ GeneratorDefinition(
+ "pekko-grpc-scaladsl-server-marshallers",
+
"org.apache.pekko.grpc.gen.scaladsl.ScalaMarshallersCodeGenerator$",
+ Seq.empty)
+ case "JavaInterfaceCodeGenerator" =>
+ GeneratorDefinition(
+ "pekko-grpc-javadsl-interface",
+ "org.apache.pekko.grpc.gen.javadsl.JavaInterfaceCodeGenerator$",
+ Seq.empty)
+ case "JavaClientCodeGenerator" =>
+ GeneratorDefinition(
+ "pekko-grpc-javadsl-client",
+ "org.apache.pekko.grpc.gen.javadsl.JavaClientCodeGenerator$",
+ Seq.empty)
+ case "JavaServerCodeGenerator" =>
+ GeneratorDefinition(
+ "pekko-grpc-javadsl-server",
+ "org.apache.pekko.grpc.gen.javadsl.JavaServerCodeGenerator$",
+ Seq.empty)
+ case _ =>
+ GeneratorDefinition(name,
s"org.apache.pekko.grpc.gen.scaladsl.$name$$", Seq.empty)
+ }
+ }
+
+ def sandboxedGenerator(definition: GeneratorDefinition):
protocbridge.Generator =
+ protocbridge.SandboxedJvmGenerator.forResolver(
+ definition.name,
+ codegenArtifact,
+ definition.suggestedDependencies,
+ new MethodHandleProtocCodeGenerator(_, definition.className,
generatorClasspath))
+
+ def scalaBaseGenerators: Seq[protocbridge.Generator] =
+ Seq(scalapb.gen.SandboxedGenerator,
sandboxedGenerator(codeGenerator("ScalaTraitCodeGenerator")))
+ def javaBaseGenerators: Seq[protocbridge.Generator] =
+ Seq(PB.gens.java,
sandboxedGenerator(codeGenerator("JavaInterfaceCodeGenerator")))
+
+ val baseGenerators = languages0 match {
+ case Seq("Scala") => scalaBaseGenerators
+ case Seq("Java") => javaBaseGenerators
+ case Seq(_, _) => scalaBaseGenerators ++ javaBaseGenerators
+ }
+
+ val stubGenerators = (for {
+ source <- sources0
+ language <- languages0
+ } yield (source, language) match {
+ case ("Client", "Scala") => codeGenerator("ScalaClientCodeGenerator")
+ case ("Server", "Scala") => codeGenerator("ScalaServerCodeGenerator")
+ case ("Client", "Java") => codeGenerator("JavaClientCodeGenerator")
+ case ("Server", "Java") => codeGenerator("JavaServerCodeGenerator")
+ }).distinct.map(sandboxedGenerator)
+
+ val generators =
+ (if (stubGenerators.nonEmpty) baseGenerators ++ stubGenerators else
stubGenerators) ++
+ extraGenerators0.map(codeGenerator).map(sandboxedGenerator)
+
+ val protocJavaSettings =
+ Set("single_line_to_proto_string", "ascii_format_to_string",
"retain_source_code_info")
+ val scalapbSettings =
+ Set("java_conversions", "flat_package", "single_line_to_proto_string",
"ascii_format_to_string", "no_lenses",
+ "retain_source_code_info", "grpc", "scala3_sources")
+
+ val generatedTargets = generators.map { generator =>
+ val settings = generator match {
+ case PB.gens.java
=> generatorSettings.filter(protocJavaSettings)
+ case protocbridge.JvmGenerator("scala", _) |
scalapb.gen.SandboxedGenerator =>
+ generatorSettings.filter(scalapbSettings)
+ case _ =>
+ generatorSettings
+ }
+ Target(generator, targetPath, settings)
+ }
+
+ targets.clear()
+ targets ++= generatedTargets
+ }
+
+ private final class MethodHandleProtocCodeGenerator(
+ classLoader: ClassLoader,
+ className: String,
+ classpath: Seq[File])
+ extends protocbridge.ProtocCodeGenerator {
+ private val childFirstClassLoader =
+ new ChildFirstClassLoader(classpath.map(_.toURI.toURL).toArray,
classLoader)
+ private val lookup = MethodHandles.publicLookup()
+ private val moduleClass = childFirstClassLoader.loadClass(className)
+ private val module =
+ lookup.findStaticGetter(moduleClass, "MODULE$",
moduleClass).invokeWithArguments()
+ private val loggerClass =
childFirstClassLoader.loadClass("org.apache.pekko.grpc.gen.Logger")
+ private val loggerModuleClass =
childFirstClassLoader.loadClass("org.apache.pekko.grpc.gen.SilencedLogger$")
+ private val logger =
+ lookup.findStaticGetter(loggerModuleClass, "MODULE$",
loggerModuleClass).invokeWithArguments()
+ private val runMethod = lookup.findVirtual(
+ moduleClass,
+ "run",
+ MethodType.methodType(classOf[Array[Byte]], classOf[Array[Byte]],
loggerClass))
+
+ override def run(request: Array[Byte]): Array[Byte] =
+ runMethod.invokeWithArguments(module, request.asInstanceOf[Object],
logger).asInstanceOf[Array[Byte]]
+
+ override def toString = s"MethodHandleProtocCodeGenerator($className)"
+ }
+
+ private final class ChildFirstClassLoader(urls: Array[URL], parent:
ClassLoader)
+ extends URLClassLoader(urls, parent) {
+ override def loadClass(name: String, resolve: Boolean): Class[?] =
+ getClassLoadingLock(name).synchronized {
+ val loaded: Class[?] = findLoadedClass(name)
+ val clazz: Class[?] =
+ if (loaded != null) loaded
+ else if (isPlatformClass(name))
ClassLoader.getPlatformClassLoader.loadClass(name)
+ else {
+ try findClass(name)
+ catch {
+ case _: ClassNotFoundException => super.loadClass(name, false)
+ }
+ }
+ if (resolve) resolveClass(clazz)
+ clazz
+ }
+
+ private def isPlatformClass(name: String): Boolean =
+ name.startsWith("java.") ||
+ name.startsWith("javax.") ||
+ name.startsWith("jdk.") ||
+ name.startsWith("sun.")
+ }
+
lazy val generateTaskFromProtocPlugin: Def.Initialize[Task[Seq[File]]] =
// lookup and return `PB.generate := ...` setting from ProtocPlugin
ProtocPlugin.projectSettings
diff --git a/project/SbtMavenPlugin.scala b/project/SbtMavenPlugin.scala
index eb459034..04c45bd9 100644
--- a/project/SbtMavenPlugin.scala
+++ b/project/SbtMavenPlugin.scala
@@ -32,7 +32,7 @@ object SbtMavenPlugin extends AutoPlugin {
import autoImport._
- override lazy val projectSettings: Seq[Setting[?]] =
inConfig(Compile)(unscopedSettings)
+ override lazy val projectSettings = inConfig(Compile)(unscopedSettings)
lazy val unscopedSettings =
Seq(
diff --git a/project/VersionGenerator.scala b/project/VersionGenerator.scala
index 42dfca49..399c38e6 100644
--- a/project/VersionGenerator.scala
+++ b/project/VersionGenerator.scala
@@ -17,7 +17,7 @@ import sbt._
*/
object VersionGenerator {
- lazy val settings: Seq[Setting[?]] = inConfig(Compile)(
+ lazy val settings = inConfig(Compile)(
Seq(
resourceGenerators += generateVersion(resourceManaged, _ /
"pekko-grpc-version.conf",
"""|pekko.grpc.version = "%s"
diff --git
a/runtime/src/main/scala/org/apache/pekko/grpc/internal/TelemetrySpi.scala
b/runtime/src/main/scala/org/apache/pekko/grpc/internal/TelemetrySpi.scala
index 67d5fa15..055d3226 100644
--- a/runtime/src/main/scala/org/apache/pekko/grpc/internal/TelemetrySpi.scala
+++ b/runtime/src/main/scala/org/apache/pekko/grpc/internal/TelemetrySpi.scala
@@ -34,6 +34,7 @@ private[internal] class TelemetryExtensionImpl(val spi:
TelemetrySpi) extends Ex
/** INTERNAL API */
@InternalStableApi
object TelemetryExtension extends ExtensionId[TelemetryExtensionImpl] with
ExtensionIdProvider {
+ @nowarn("msg=the inferred type changes")
override def lookup = TelemetryExtension
override def createExtension(system: ExtendedActorSystem) =
new TelemetryExtensionImpl(TelemetrySpi(system))
diff --git
a/runtime/src/main/scala/org/apache/pekko/grpc/javadsl/ServerReflection.scala
b/runtime/src/main/scala/org/apache/pekko/grpc/javadsl/ServerReflection.scala
index 35b68a9e..e5de352c 100644
---
a/runtime/src/main/scala/org/apache/pekko/grpc/javadsl/ServerReflection.scala
+++
b/runtime/src/main/scala/org/apache/pekko/grpc/javadsl/ServerReflection.scala
@@ -32,8 +32,9 @@ object ServerReflection {
objects: Collection[ServiceDescription],
sys: ClassicActorSystemProvider):
pekko.japi.function.Function[HttpRequest, CompletionStage[HttpResponse]] = {
import scala.jdk.CollectionConverters._
+ implicit val system: ClassicActorSystemProvider = sys
val delegate = ServerReflectionHandler.apply(
- ServerReflectionImpl(objects.asScala.map(_.descriptor).toSeq,
objects.asScala.map(_.name).toList))(sys)
+ ServerReflectionImpl(objects.asScala.map(_.descriptor).toSeq,
objects.asScala.map(_.name).toList))
import scala.jdk.FutureConverters._
request =>
delegate
diff --git
a/runtime/src/main/scala/org/apache/pekko/grpc/javadsl/ServiceHandler.scala
b/runtime/src/main/scala/org/apache/pekko/grpc/javadsl/ServiceHandler.scala
index a01303da..4a9bbdda 100644
--- a/runtime/src/main/scala/org/apache/pekko/grpc/javadsl/ServiceHandler.scala
+++ b/runtime/src/main/scala/org/apache/pekko/grpc/javadsl/ServiceHandler.scala
@@ -46,7 +46,7 @@ object ServiceHandler {
@varargs
def concatOrNotFound(handlers: JFunction[HttpRequest,
CompletionStage[HttpResponse]]*)
: JFunction[HttpRequest, CompletionStage[HttpResponse]] =
- handler(handlers: _*)
+ handler(handlers *)
/**
* Creates a `HttpRequest` to `HttpResponse` handler for gRPC services that
can be used in
@@ -56,7 +56,7 @@ object ServiceHandler {
@varargs
def handler(handlers: JFunction[HttpRequest, CompletionStage[HttpResponse]]*)
: JFunction[HttpRequest, CompletionStage[HttpResponse]] = {
- val servicesHandler = concat(handlers: _*)
+ val servicesHandler = concat(handlers *)
(req: HttpRequest) => servicesHandler(req)
}
diff --git
a/runtime/src/main/scala/org/apache/pekko/grpc/javadsl/WebHandler.scala
b/runtime/src/main/scala/org/apache/pekko/grpc/javadsl/WebHandler.scala
index 627c4df5..7f4d748d 100644
--- a/runtime/src/main/scala/org/apache/pekko/grpc/javadsl/WebHandler.scala
+++ b/runtime/src/main/scala/org/apache/pekko/grpc/javadsl/WebHandler.scala
@@ -77,7 +77,7 @@ object WebHandler {
corsSettings: CorsSettings): JFunction[HttpRequest,
CompletionStage[HttpResponse]] = {
import scala.jdk.CollectionConverters._
- val servicesHandler = concatOrNotFound(handlers.asScala.toList: _*)
+ val servicesHandler = concatOrNotFound(handlers.asScala.toList *)
val servicesRoute =
RouteAdapter(MarshallingDirectives.handleWith(servicesHandler.apply(_)))
val handler = asyncHandler(CorsDirectives.cors(corsSettings, () =>
servicesRoute), as, mat)
(req: HttpRequest) =>
diff --git a/runtime/src/main/scala/org/apache/pekko/grpc/scaladsl/Grpc.scala
b/runtime/src/main/scala/org/apache/pekko/grpc/scaladsl/Grpc.scala
index 63bf2a7c..24aabe40 100644
--- a/runtime/src/main/scala/org/apache/pekko/grpc/scaladsl/Grpc.scala
+++ b/runtime/src/main/scala/org/apache/pekko/grpc/scaladsl/Grpc.scala
@@ -39,7 +39,8 @@ private[grpc] final class GrpcImpl(system:
ExtendedActorSystem) extends Extensio
.map(channel =>
channel.close().recover {
case e =>
- val log = Logging(system, getClass)(LogSource.fromClass)
+ implicit val logSource: LogSource[Class[?]] =
LogSource.fromClass
+ val log = Logging(system, getClass)
log.warning("Failed to gracefully close {}, proceeding with
shutdown anyway. {}", channel, e)
Done
}))
diff --git
a/runtime/src/main/scala/org/apache/pekko/grpc/scaladsl/ServiceHandler.scala
b/runtime/src/main/scala/org/apache/pekko/grpc/scaladsl/ServiceHandler.scala
index c816321a..b020474a 100644
--- a/runtime/src/main/scala/org/apache/pekko/grpc/scaladsl/ServiceHandler.scala
+++ b/runtime/src/main/scala/org/apache/pekko/grpc/scaladsl/ServiceHandler.scala
@@ -38,7 +38,7 @@ object ServiceHandler {
def concatOrNotFound(
handlers: PartialFunction[HttpRequest, Future[HttpResponse]]*):
HttpRequest => Future[HttpResponse] =
- concat(handlers: _*).orElse { case _ => notFound }
+ concat(handlers *).orElse { case _ => notFound }
def concat(handlers: PartialFunction[HttpRequest, Future[HttpResponse]]*)
: PartialFunction[HttpRequest, Future[HttpResponse]] =
diff --git
a/runtime/src/main/scala/org/apache/pekko/grpc/scaladsl/WebHandler.scala
b/runtime/src/main/scala/org/apache/pekko/grpc/scaladsl/WebHandler.scala
index 97240dda..6391b51d 100644
--- a/runtime/src/main/scala/org/apache/pekko/grpc/scaladsl/WebHandler.scala
+++ b/runtime/src/main/scala/org/apache/pekko/grpc/scaladsl/WebHandler.scala
@@ -63,7 +63,7 @@ object WebHandler {
implicit as: ClassicActorSystemProvider,
corsSettings: CorsSettings = defaultCorsSettings): HttpRequest =>
Future[HttpResponse] = {
implicit val system: ActorSystem = as.classicSystem
- val servicesHandler = ServiceHandler.concat(handlers: _*)
+ val servicesHandler = ServiceHandler.concat(handlers *)
Route.toFunction(cors(corsSettings) {
handleWith(servicesHandler)
})
diff --git
a/runtime/src/main/scala/org/apache/pekko/grpc/scaladsl/headers/headers.scala
b/runtime/src/main/scala/org/apache/pekko/grpc/scaladsl/headers/headers.scala
index eab0e002..7c894dfa 100644
---
a/runtime/src/main/scala/org/apache/pekko/grpc/scaladsl/headers/headers.scala
+++
b/runtime/src/main/scala/org/apache/pekko/grpc/scaladsl/headers/headers.scala
@@ -21,6 +21,7 @@ import pekko.http.javadsl.{ model => jm }
import scala.collection.compat.immutable.ArraySeq
import scala.collection.immutable
+import scala.annotation.nowarn
import scala.util.Try
@ApiMayChange
@@ -28,6 +29,7 @@ final class `Message-Accept-Encoding`(override val value:
String)
extends ModeledCustomHeader[`Message-Accept-Encoding`] {
override def renderInRequests = true
override def renderInResponses = true
+ @nowarn("msg=the inferred type changes")
override val companion = `Message-Accept-Encoding`
lazy val values: Array[String] = value.split(',')
@@ -55,6 +57,7 @@ object `Message-Accept-Encoding` extends
ModeledCustomHeaderCompanion[`Message-A
final class `Message-Encoding`(encoding: String) extends
ModeledCustomHeader[`Message-Encoding`] {
override def renderInRequests = true
override def renderInResponses = true
+ @nowarn("msg=the inferred type changes")
override val companion = `Message-Encoding`
override def value: String = encoding
}
@@ -79,6 +82,7 @@ object `Message-Encoding` extends
ModeledCustomHeaderCompanion[`Message-Encoding
final class `Status`(code: Int) extends ModeledCustomHeader[`Status`] {
override def renderInRequests = false
override def renderInResponses = true
+ @nowarn("msg=the inferred type changes")
override val companion = `Status`
override def value() = code.toString
@@ -98,6 +102,7 @@ object `Status` extends
ModeledCustomHeaderCompanion[`Status`] {
final class `Status-Message`(val unencodedValue: String) extends
ModeledCustomHeader[`Status-Message`] {
override def renderInRequests = false
override def renderInResponses = true
+ @nowarn("msg=the inferred type changes")
override val companion = `Status-Message`
override def value() = PercentEncoding.Encoder.encode(unencodedValue)
}
diff --git
a/runtime/src/test/scala/org/apache/pekko/grpc/internal/PekkoDiscoveryNameResolverSpec.scala
b/runtime/src/test/scala/org/apache/pekko/grpc/internal/PekkoDiscoveryNameResolverSpec.scala
index bd339996..bfd3dc92 100644
---
a/runtime/src/test/scala/org/apache/pekko/grpc/internal/PekkoDiscoveryNameResolverSpec.scala
+++
b/runtime/src/test/scala/org/apache/pekko/grpc/internal/PekkoDiscoveryNameResolverSpec.scala
@@ -53,8 +53,7 @@ class PekkoDiscoveryNameResolverSpec
}
"support serving a static host/port" in {
- // Unfortunately it needs to be an actually resolvable address...
- val host = "akka.io"
+ val host = "localhost"
val port = 4040
val resolver =
PekkoDiscoveryNameResolver(GrpcClientSettings.connectToServiceAt(host, port))
val probe = new NameResolverListenerProbe()
diff --git
a/sbt-plugin/src/main/scala-2/org/apache/pekko/grpc/sbt/PackageMappingCompat.scala
b/sbt-plugin/src/main/scala-2/org/apache/pekko/grpc/sbt/PackageMappingCompat.scala
new file mode 100644
index 00000000..6bce92d7
--- /dev/null
+++
b/sbt-plugin/src/main/scala-2/org/apache/pekko/grpc/sbt/PackageMappingCompat.scala
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.pekko.grpc.sbt
+
+import scala.annotation.nowarn
+
+import java.io.File
+
+import xsbti.FileConverter
+
+private[sbt] object PackageMappingCompat {
+ type PackageMapping = (File, String)
+
+ def packageMapping(file: File, path: String, @nowarn("msg=is never used")
fileConverter: FileConverter)
+ : PackageMapping =
+ file -> path
+}
diff --git
a/sbt-plugin/src/main/scala-3/org/apache/pekko/grpc/sbt/PackageMappingCompat.scala
b/sbt-plugin/src/main/scala-3/org/apache/pekko/grpc/sbt/PackageMappingCompat.scala
new file mode 100644
index 00000000..c58982d1
--- /dev/null
+++
b/sbt-plugin/src/main/scala-3/org/apache/pekko/grpc/sbt/PackageMappingCompat.scala
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.pekko.grpc.sbt
+
+import java.io.File
+
+import xsbti.{ FileConverter, HashedVirtualFileRef }
+
+private[sbt] object PackageMappingCompat {
+ type PackageMapping = (HashedVirtualFileRef, String)
+
+ def packageMapping(file: File, path: String, fileConverter: FileConverter):
PackageMapping =
+ fileConverter.toVirtualFile(file.toPath) -> path
+}
diff --git
a/sbt-plugin/src/main/scala/org/apache/pekko/grpc/sbt/PekkoGrpcPlugin.scala
b/sbt-plugin/src/main/scala/org/apache/pekko/grpc/sbt/PekkoGrpcPlugin.scala
index 3d615020..754a40c6 100644
--- a/sbt-plugin/src/main/scala/org/apache/pekko/grpc/sbt/PekkoGrpcPlugin.scala
+++ b/sbt-plugin/src/main/scala/org/apache/pekko/grpc/sbt/PekkoGrpcPlugin.scala
@@ -120,23 +120,17 @@ object PekkoGrpcPlugin extends AutoPlugin {
packageBin / mappings := {
val existingMappings = (packageBin / mappings).value
val unpackedFiles = PB.unpackDependencies.value.files
+ val converter = fileConverter.value
val mappingsToAdd =
-
unpackedFiles.pair(Path.relativeTo(Seq(PB.externalSourcePath.value,
PB.externalIncludePath.value)))
- @scala.annotation.tailrec
- def withoutDuplicates(soFar: List[(File, String)], seen:
Set[String], toAdd: Seq[(File, String)])
- : Seq[(File, String)] = {
- toAdd.headOption match {
- case Some((file, string)) =>
- if (seen.contains(string)) {
- withoutDuplicates(soFar, seen, toAdd.tail)
- } else {
- withoutDuplicates((file, string) :: soFar, seen + string,
toAdd.tail)
- }
- case None =>
- soFar
- }
- }
- withoutDuplicates(existingMappings.toList,
existingMappings.map(_._2).toSet, mappingsToAdd)
+ unpackedFiles
+ .pair(Path.relativeTo(Seq(PB.externalSourcePath.value,
PB.externalIncludePath.value)))
+ .map { case (file, path) =>
PackageMappingCompat.packageMapping(file, path, converter) }
+ (existingMappings.toList ++
mappingsToAdd).foldLeft((List.empty[PackageMappingCompat.PackageMapping],
+ Set.empty[String])) {
+ case ((soFar, seen), mapping @ (_, path)) =>
+ if (seen(path)) (soFar, seen)
+ else (mapping :: soFar, seen + path)
+ }._1.reverse
},
unmanagedResourceDirectories ++= (PB.recompile /
unmanagedResourceDirectories).value,
Defaults.ConfigZero / watchSources ++= Def.uncached {
@@ -154,7 +148,7 @@ object PekkoGrpcPlugin extends AutoPlugin {
PB.targets ++=
targetsFor(
(pekkoGrpcCodeGeneratorSettings / target).value,
- pekkoGrpcCodeGeneratorSettings.value,
+ pekkoGrpcCodeGeneratorSettings.value ++
scala3SourcesSettings.value,
pekkoGrpcGenerators.value),
PB.protoSources += sourceDirectory.value / "proto"))
@@ -176,6 +170,9 @@ object PekkoGrpcPlugin extends AutoPlugin {
})
}
+ private def scala3SourcesSettings: Def.Initialize[Seq[String]] =
+ Def.setting(if (scalaBinaryVersion.value == "3") Seq("scala3_sources")
else Seq.empty)
+
// creates a seq of generator and per generator settings
def generatorsFor(
stubs: Seq[PekkoGrpc.GeneratedSource],
diff --git
a/sbt-plugin/src/sbt-test/gen-scala-server/02-multiple-services/src/main/scala/example/myapp/Main.scala
b/sbt-plugin/src/sbt-test/gen-scala-server/02-multiple-services/src/main/scala/example/myapp/Main.scala
index 8afa412c..33f33175 100644
---
a/sbt-plugin/src/sbt-test/gen-scala-server/02-multiple-services/src/main/scala/example/myapp/Main.scala
+++
b/sbt-plugin/src/sbt-test/gen-scala-server/02-multiple-services/src/main/scala/example/myapp/Main.scala
@@ -24,16 +24,18 @@ import example.myapp.echo.grpc.EchoServiceHandler
import example.myapp.helloworld.GreeterServiceImpl
import example.myapp.helloworld.grpc.GreeterServiceHandler
-object Main extends App {
- implicit val system: ActorSystem = ActorSystem()
+object Main {
+ def main(args: Array[String]): Unit = {
+ implicit val system: ActorSystem = ActorSystem()
- val echoHandler = EchoServiceHandler.partial(new EchoServiceImpl)
- val greeterHandler = GreeterServiceHandler.partial(new GreeterServiceImpl)
- val serviceHandler = ServiceHandler.concatOrNotFound(echoHandler,
greeterHandler)
+ val echoHandler = EchoServiceHandler.partial(new EchoServiceImpl)
+ val greeterHandler = GreeterServiceHandler.partial(new GreeterServiceImpl)
+ val serviceHandler = ServiceHandler.concatOrNotFound(echoHandler,
greeterHandler)
- Http().newServerAt("localhost", 8443)
- .enableHttps(serverHttpContext())
- .bind(serviceHandler)
+ Http().newServerAt("localhost", 8443)
+ .enableHttps(serverHttpContext())
+ .bind(serviceHandler)
+ }
private def serverHttpContext() = {
// never put passwords into code!
diff --git
a/sbt-plugin/src/sbt-test/gen-scala-server/04-server-reflection/src/main/scala/example/myapp/helloworld/Main.scala
b/sbt-plugin/src/sbt-test/gen-scala-server/04-server-reflection/src/main/scala/example/myapp/helloworld/Main.scala
index 431445df..3f47be9e 100644
---
a/sbt-plugin/src/sbt-test/gen-scala-server/04-server-reflection/src/main/scala/example/myapp/helloworld/Main.scala
+++
b/sbt-plugin/src/sbt-test/gen-scala-server/04-server-reflection/src/main/scala/example/myapp/helloworld/Main.scala
@@ -29,48 +29,50 @@ import example.myapp.helloworld.grpc._
//#server-reflection
-object Main extends App {
- val conf = ConfigFactory
- .parseString("pekko.http.server.enable-http2 = on")
- .withFallback(ConfigFactory.defaultApplication())
- implicit val sys: ActorSystem = ActorSystem("HelloWorld", conf)
-
- implicit val ec: ExecutionContext = sys.dispatcher
-
- // #server-reflection
- // Create service handler with a fallback to a Server Reflection handler.
- // `.withServerReflection` is a convenience method that contacts a partial
- // function of the provided service with a reflection handler for that
- // same service.
- val greeter: HttpRequest => Future[HttpResponse] =
- GreeterServiceHandler.withServerReflection(new GreeterServiceImpl())
-
- // Bind service handler servers to localhost:8080
- val binding = Http().newServerAt("127.0.0.1", 8080)
- .bind(greeter)
- // #server-reflection
-
- // report successful binding
- binding.foreach { binding =>
- println(s"gRPC server bound to: ${binding.localAddress}")
+object Main {
+ def main(args: Array[String]): Unit = {
+ val conf = ConfigFactory
+ .parseString("pekko.http.server.enable-http2 = on")
+ .withFallback(ConfigFactory.defaultApplication())
+ implicit val sys: ActorSystem = ActorSystem("HelloWorld", conf)
+
+ implicit val ec: ExecutionContext = sys.dispatcher
+
+ // #server-reflection
+ // Create service handler with a fallback to a Server Reflection handler.
+ // `.withServerReflection` is a convenience method that contacts a partial
+ // function of the provided service with a reflection handler for that
+ // same service.
+ val greeter: HttpRequest => Future[HttpResponse] =
+ GreeterServiceHandler.withServerReflection(new GreeterServiceImpl())
+
+ // Bind service handler servers to localhost:8080
+ val binding = Http().newServerAt("127.0.0.1", 8080)
+ .bind(greeter)
+ // #server-reflection
+
+ // report successful binding
+ binding.foreach { binding =>
+ println(s"gRPC server bound to: ${binding.localAddress}")
+ }
+
+ // #server-reflection-manual-concat
+ // Create service handlers
+ val greeterPartial: PartialFunction[HttpRequest, Future[HttpResponse]] =
+ GreeterServiceHandler.partial(new GreeterServiceImpl(),
"greeting-prefix")
+ val echoPartial: PartialFunction[HttpRequest, Future[HttpResponse]] =
+ EchoServiceHandler.partial(new EchoServiceImpl())
+ // Create the reflection handler for multiple services
+ val reflection =
+ ServerReflection.partial(List(GreeterService, EchoService))
+
+ // Concatenate the partial functions into a single handler
+ val handler =
+ ServiceHandler.concatOrNotFound(
+ greeterPartial,
+ echoPartial,
+ reflection)
+ // #server-reflection-manual-concat
}
- // #server-reflection-manual-concat
- // Create service handlers
- val greeterPartial: PartialFunction[HttpRequest, Future[HttpResponse]] =
- GreeterServiceHandler.partial(new GreeterServiceImpl(), "greeting-prefix")
- val echoPartial: PartialFunction[HttpRequest, Future[HttpResponse]] =
- EchoServiceHandler.partial(new EchoServiceImpl())
- // Create the reflection handler for multiple services
- val reflection =
- ServerReflection.partial(List(GreeterService, EchoService))
-
- // Concatenate the partial functions into a single handler
- val handler =
- ServiceHandler.concatOrNotFound(
- greeterPartial,
- echoPartial,
- reflection)
- // #server-reflection-manual-concat
-
}
diff --git
a/sbt-plugin/src/sbt-test/gen-scala-server/10-scalapb-validate/src/main/scala/example/myapp/Main.scala
b/sbt-plugin/src/sbt-test/gen-scala-server/10-scalapb-validate/src/main/scala/example/myapp/Main.scala
index 94210ea8..fa1894e8 100644
---
a/sbt-plugin/src/sbt-test/gen-scala-server/10-scalapb-validate/src/main/scala/example/myapp/Main.scala
+++
b/sbt-plugin/src/sbt-test/gen-scala-server/10-scalapb-validate/src/main/scala/example/myapp/Main.scala
@@ -14,16 +14,18 @@ import scalapb.validate._
import example.myapp.helloworld.grpc.HelloRequest
-object Main extends App {
+object Main {
+ def main(args: Array[String]): Unit = {
- Try(HelloRequest("valid")) match {
- case Success(_) => // expected
- case Failure(e) => throw new RuntimeException("unexpected violations for
\"valid\"", e)
- }
+ Try(HelloRequest("valid")) match {
+ case Success(_) => // expected
+ case Failure(e) => throw new RuntimeException("unexpected violations for
\"valid\"", e)
+ }
- Try(HelloRequest("ko")) match {
- case Success(_) => throw new RuntimeException("unexpected success for
\"ko\"")
- case Failure(e) => // expected
+ Try(HelloRequest("ko")) match {
+ case Success(_) => throw new RuntimeException("unexpected success for
\"ko\"")
+ case Failure(e) => // expected
+ }
}
}
diff --git a/sbt-plugin/src/sbt-test/scala3/01-basic-client-server/build.sbt
b/sbt-plugin/src/sbt-test/scala3/01-basic-client-server/build.sbt
index 14a49e49..b4411f23 100644
--- a/sbt-plugin/src/sbt-test/scala3/01-basic-client-server/build.sbt
+++ b/sbt-plugin/src/sbt-test/scala3/01-basic-client-server/build.sbt
@@ -7,9 +7,15 @@
* This file is part of the Apache Pekko project, which was derived from Akka.
*/
-scalaVersion := "3.3.8"
+scalaVersion := sys.props.getOrElse(
+ "pekko.grpc.scala3.next.version",
+ sys.error("pekko.grpc.scala3.next.version must be provided by
scriptedLaunchOpts"))
-scalacOptions += "-Xfatal-warnings"
+scalacOptions ++= Seq(
+ "-Werror",
+ "-Wconf:msg=Implicit parameters should be provided with a `using` clause:s",
+ "-Wconf:msg=Ignoring \\[this\\] qualifier:s",
+ "-Wconf:msg=`_` is deprecated for wildcard arguments of types:s")
enablePlugins(PekkoGrpcPlugin)
diff --git a/sbt-plugin/src/sbt-test/scala3/02-scala3-sourcegen/build.sbt
b/sbt-plugin/src/sbt-test/scala3/02-scala3-sourcegen/build.sbt
index 6bacc82e..5c6cd01a 100644
--- a/sbt-plugin/src/sbt-test/scala3/02-scala3-sourcegen/build.sbt
+++ b/sbt-plugin/src/sbt-test/scala3/02-scala3-sourcegen/build.sbt
@@ -7,9 +7,13 @@
* This file is part of the Apache Pekko project, which was derived from Akka.
*/
-scalaVersion := "3.3.8"
+scalaVersion := sys.props.getOrElse(
+ "pekko.grpc.scala3.next.version",
+ sys.error("pekko.grpc.scala3.next.version must be provided by
scriptedLaunchOpts"))
-scalacOptions += "-Xfatal-warnings"
+scalacOptions ++= Seq(
+ "-Werror",
+ "-Wconf:msg=Implicit parameters should be provided with a `using` clause:s")
enablePlugins(PekkoGrpcPlugin)
diff --git a/sbt-plugin/src/sbt-test/scala3/03-sbt2-basic/build.sbt
b/sbt-plugin/src/sbt-test/scala3/03-sbt2-basic/build.sbt
index 8509801e..e4134ab0 100644
--- a/sbt-plugin/src/sbt-test/scala3/03-sbt2-basic/build.sbt
+++ b/sbt-plugin/src/sbt-test/scala3/03-sbt2-basic/build.sbt
@@ -7,8 +7,14 @@
* This file is part of the Apache Pekko project, which was derived from Akka.
*/
-// Verify that the pekko-grpc sbt plugin cross-builds correctly for sbt 1.x
and sbt 2.x.
-// When run in the Scala 3 build pass (+scripted), scriptedSbt is set to 2.x.y.
-scalaVersion := "3.3.7"
+// Verify that the pekko-grpc sbt plugin cross-builds correctly for sbt 2.x.
+scalaVersion := sys.props.getOrElse(
+ "pekko.grpc.scala3.next.version",
+ sys.error("pekko.grpc.scala3.next.version must be provided by
scriptedLaunchOpts"))
+
+scalacOptions ++= Seq(
+ "-Wconf:msg=Implicit parameters should be provided with a `using` clause:s",
+ "-Wconf:msg=Ignoring \\[this\\] qualifier:s",
+ "-Wconf:msg=`_` is deprecated for wildcard arguments of types:s")
enablePlugins(PekkoGrpcPlugin)
diff --git
a/scalapb-protoc-plugin/src/main/scala/org/apache/pekko/grpc/scalapb/Main.scala
b/scalapb-protoc-plugin/src/main/scala/org/apache/pekko/grpc/scalapb/Main.scala
index fcbf6132..21032602 100644
---
a/scalapb-protoc-plugin/src/main/scala/org/apache/pekko/grpc/scalapb/Main.scala
+++
b/scalapb-protoc-plugin/src/main/scala/org/apache/pekko/grpc/scalapb/Main.scala
@@ -17,21 +17,23 @@ import java.io.ByteArrayOutputStream
import scalapb.ScalaPbCodeGenerator
-object Main extends App {
- val inBytes: Array[Byte] = {
- val baos = new ByteArrayOutputStream(math.max(64, System.in.available()))
- val buffer = Array.ofDim[Byte](32 * 1024)
-
- var bytesRead = System.in.read(buffer)
- while (bytesRead >= 0) {
- baos.write(buffer, 0, bytesRead)
- bytesRead = System.in.read(buffer)
+object Main {
+ def main(args: Array[String]): Unit = {
+ val inBytes: Array[Byte] = {
+ val baos = new ByteArrayOutputStream(math.max(64, System.in.available()))
+ val buffer = Array.ofDim[Byte](32 * 1024)
+
+ var bytesRead = System.in.read(buffer)
+ while (bytesRead >= 0) {
+ baos.write(buffer, 0, bytesRead)
+ bytesRead = System.in.read(buffer)
+ }
+ baos.toByteArray
}
- baos.toByteArray
- }
- val outBytes = ScalaPbCodeGenerator.run(inBytes)
+ val outBytes = ScalaPbCodeGenerator.run(inBytes)
- System.out.write(outBytes)
- System.out.flush()
+ System.out.write(outBytes)
+ System.out.flush()
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]