Skip to content

Scala3 Play3 Apache Pekko migration#2595

Open
mathieuancelin wants to merge 71 commits into
masterfrom
scala3-play3-pekko-migration
Open

Scala3 Play3 Apache Pekko migration#2595
mathieuancelin wants to merge 71 commits into
masterfrom
scala3-play3-pekko-migration

Conversation

@mathieuancelin

@mathieuancelin mathieuancelin commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Of course AI assisted

- sbt 1.7.2 → 1.12.5 ; sbt-plugin com.typesafe.play 2.8.19 → org.playframework 3.0.10
- plugin bumps (scalafmt/revolver/bloop/pgp/ci-release) + sbt-assembly 2.3.1 (remplace project/assembly.sbt 0.14.6)
- build.sbt : Scala 3.8.3, play-json 3.0.6, akka→pekko 1.6.0 / pekko-http 1.3.0 / connectors,
  jackson 2.21.3, macwire 2.6.7, rediscala fork 2.0.2, scaffeine 5.3.0, sangria 4.2.18,
  diffson 4.7.0, wasm4s 5.0.3, pulsar4s-pekko-streams 2.10.0, scalatestplus-play 7.0.2,
  censorinus via for3Use2_13
- on garde toutes les libs Java aux versions actuelles (netty/reactor-netty, k8s, lettuce,
  vertx-pg, bouncycastle, opentelemetry…) pour éviter des changements de code hors-migration
- drop kaleidoscope (réécrite en Phase 3) et swagger-scala-module (pas de build Scala 3) ;
  on garde swagger-core-jakarta (Java)
- suppression du jar akka-stream patché (le fix TLS 1.3 est dans Pekko 1.6 upstream) et du
  jar scala-schema inutilisé ; hook Twirl adhocExtensions pour Scala 3.8 ; drop PlayAkkaHttp2Support

Résolution des dépendances (sbt update) verte.
- app/ + test/: `akka.` → `org.apache.pekko.` (855 imports, ~315 files)
- alpakka → pekko connectors: `akka.stream.alpakka` → `org.apache.pekko.stream.connectors` (s3)
- `akka.kafka` → `org.apache.pekko.kafka`
- app/tcp/tcputils.scala: `package akka` → `package org.apache.pekko` (keeps in-package access
  to NotUsed/Done and stream internals, no more patched akka-stream)
- app/utils/akka.scala: reflective field name mangled for the pekko package
  (akka$http$… → org$apache$pekko$http$…) for the open-charset json media type hook
- conf: actorsystem blocks `akka {` → `pekko {`, `${akka.version}`/`${akka.http.parsing.*}`
  → `${pekko.*}`, `play.server.akka` → `play.server.pekko`, pekko.version "2.6.20" → "1.6.0",
  logback akka logger → org.apache.pekko ; kept otoroshi keys (enforce-akka, OTOROSHI_AKKA_*
  env vars, "Otoroshi-akka" user-agent, metadata keys)

Otoroshi's own Akka-named identifiers/strings (useAkkaHttpClient, AkkaWsClientRequest,
"otoroshi-core-use-akka-http-client", logger names…) are intentionally left unchanged.
- kaleidoscope (macro-based Scala 2 lib, unusable from Scala 3): add a tiny non-macro shim
  otoroshi.utils.KaleidoscopeShim that re-implements the old `r"...$name@(regex)"` pattern
  interpolator with String captures, and swap `import kaleidoscope._` → the shim in the 7 files
  that used it. All ~117 `case r"…"` call-sites (incl. el.scala's 106) stay unchanged.
- TemplatesController.templateSpec: `scala.reflect.runtime.universe` / `typeOf` don't exist at
  runtime in Scala 3 → derive event field paths with plain Java reflection (Product + declared
  fields, unwrap parameterized fields, visited-set against cycles); `typeOf[T]` → `classOf[T]`.
- Env.scala: drop the SwaggerScalaModelConverter registration (swagger-scala-module has no Scala 3
  build and pulls Akka); api.scala already falls back to a generic schema.
…plicit types

- build.sbt: add -source:3.0-migration so Scala 2.13 syntax (e.g. un-parenthesized typed
  lambda params) is accepted as warnings instead of errors — keeps the diff minimal
- backtick `export` / `enum` used as identifiers (now hard keywords in Scala 3)
- add explicit types to ~400 `implicit (lazy) val NAME = rhs` (Scala 3 requires them):
  ExecutionContext / Materializer / Scheduler / ActorSystem / OFormat / Format / Env,
  fully-qualified to avoid import churn

Compile errors: 1874 → 566.
… fixes

- annotate the lambda param of sync `XxxAction { ctx => ... }` and `actionBuilder { req => }`
  call-sites: Play 3's ActionBuilder.apply(block) is ambiguous with apply(bodyParser) in Scala 3
  because BodyParser is a SAM (RequestHeader => Accumulator) — the param type disambiguates
- `.mapValues(f)` → `.mapValues(f).toMap` (Scala 2.13 returns a lazy MapView, rejected where a Map
  is required, e.g. JsObject(...))
- `Env.metrics`: annotate `: Metrics` — a member overriding HasMetrics.metrics without an explicit
  type now inherits the parent type (TimerMetrics) in Scala 3, hiding histogramUpdate/counterInc/…
- script.scala class scans: `.map(_.getName)` → `.map(_.getName).toSeq` (asScala yields mutable.Buffer)
- adminEntityValidators parsing: `.collect{…}` → `.collect{…}.toSeq` (JsArray.value is IndexedSeq,
  union-typed away from the expected Map[String, Seq[JsonValidator]])
…er, JsonValidator toSeq

- implicit-first modifier order (implicit private val …) now also gets explicit types (netty server)
- brace-form .mapValues { … } → .toMap (Scala 2.13 MapView), mirroring the paren-form fix
- SAMLClient: import scala.jdk.CollectionConverters._ (asScalaBufferConverter is not in scala.jdk)

Compile errors: 347 → 308.
…r paren/parser forms

- scala.collection.mutable.MutableList (removed in 2.13) → ListBuffer
- reactor-netty .secure(spec => …): make the lambda Unit-returning for the Java Consumer SAM
- annotate remaining ambiguous ActionBuilder forms: ApiAction(ctx => …) paren form and
  BackOfficeActionAuth(parse.json) { ctx => … } parser form

Compile errors: 308 → 278.
- treerouter NgMatchedRoutes(routes,…): routes is a mutable ListBuffer → .toSeq for immutable Seq
- chains ending in .getOrElse(Seq.empty[X]) whose .map branch yields collection.Seq (JsArray.value)
  no longer conform to the immutable Seq field type → append .toSeq

Compile errors: 278 → 233.
…to-tupling, WSResponse.body[String]

- import scala.jdk.CollectionConverters._ (named converters like mapAsScalaMapConverter are not in scala.jdk)
- response.scala: rename lambda param r → mr to avoid clash with the KaleidoscopeShim  interpolator
- restore explicit tuples for println(...) (Scala 3 removed auto-tupling)
- resp.body → resp.body[String] (WSResponse.body BodyReadable is ambiguous in Scala 3)
…onfig type

Compile errors: 233 → (see next).
…ollection.IndexedSeq, ClassTag Array.empty[String]
…nents, PekkoSSLConfig, breakOut→toSet, Right/rbac/polyfill/cookies toSeq
…llect(), more toSeq (oauth/workflow/teams/analytics), script.scala JsError collection.Seq
….collect toSeq (oidc/EntityFiltering/OpenapiToJson)
…wed by otoroshi.utils.Regex), gzip breakOut, filterKeys/coraza toSeq
…param, izanami response type, sangria InterfaceTypeDefinition interfaces=
…iceArrayWithArgs collection.Seq, OpenapiToJson/oidc/sources/netty toSeq, coraza wasm host fns
…s JavaConverters, netty request varargs toSeq
…ing], api.scala headers immutable, graphql validateQuery args, html applyOnIf explicit lambda, sources/entities toSeq
…If existential, graphql untag urlArg, vertx pool.close handler
…scription, kubernetes body[String]/toSeq, coraza immutable Seq
…ubs, coraza Seq import, xml class not case-class, sangria validateQuery 4-arg
Zwiterrion and others added 30 commits July 2, 2026 17:46
(cherry picked from commit 501e17d)
(cherry picked from commit 3b2e86c)
(cherry picked from commit f5032a2)
The cherry-picked test from release 17.17.0 used the old ScalaTest 3.0
API (org.scalatest.{MustMatchers, WordSpec}) which no longer exists in
the ScalaTest 3.2+ used on this branch. Switch to AnyWordSpec + must.Matchers
to match the migrated tests convention.
Reconcile the branch with master so PR #2595 becomes mergeable.

Conflict resolution:
- el.scala, oidc.scala, apikey.scala, elasticsearch.js: kept the Scala 3
  branch versions (the release fixes were already backported here; the only
  differences were scalafmt/prettier formatting).
- ElasticWritesAnalyticsSpec.scala: kept the Scala 3 version (ScalaTest 3.2
  AnyWordSpec/must.Matchers API), master's used the removed ScalaTest 3.0 API.
- build.sbt: took master's version 17.18.0-dev.

Verified: sbt compile and sbt Test/compile both succeed.
Removed the call to ElasticWritesAnalytics.initialized for compatibility with newer Elastic versions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants