Background
StreamPark was originally built with a Scala-first development model: user applications extend FlinkStreaming / FlinkTable / SparkStreaming / SparkBatch traits; Flink multi-version support is implemented via Scala shims behind FlinkShimsProxy; and most runtime modules (streampark-common, Flink client/K8s/packer, Spark client) are written in Scala.
This creates several long-term costs:
- Build complexity:
scala-maven-plugin, Scalafmt, Scalastyle, silencer, ScalaTest, and mixed Java/Scala compilation increase CI time and contributor onboarding friction.
- Ecosystem alignment: Apache Flink 2.x removed the Scala DataStream API; continuing Scala-centric APIs fights upstream direction.
- Console alignment:
streampark-console-service is Java/Spring Boot but depends heavily on Scala-compiled libraries (HadoopUtils, FlinkClient, FlinkShimsProxy, packer pipelines, etc.).
- Maintenance multiplier: Every shims change must be replicated across many Flink version modules, most of which are Scala.
#4432 removed the user-facing dev framework and connector wrappers. Flink SQL jobs now run through SqlClient → versioned StreamTableContext / TableContext → FlinkSqlExecutor. Structural refactors on that path must preserve external behavior.
This issue tracks the design and execution plan to remove Scala from the StreamPark codebase and safely refactor the Flink SQL submission stack.
Implementation PRs: #4458, #4461 merged; #4462–#4464 in review (stacked)
Depends on: #4409 (JDK 11 baseline ✅), #4432 (dev framework removal ✅)
Parent roadmap: #4410
Community workflow (PMC sync): migrate class-by-class; each new Java class should ship with tests (or document why not). Sub-task issues: #4445 #4446 #4447 #4448 #4449 #4450 #4451 #4452 #4453 — link PRs to the matching row below. Opening a separate GitHub issue per class is optional when you want an isolated review thread.
Progress Update (2026-07-29)
Overall: Stage 1 is ~75% landed on dev; Stage 2 stacked PRs (#4463, #4464) are in flight.
| Milestone |
Issue |
PR |
Status |
streampark-common |
#4445 |
#4458 |
✅ Merged |
streampark-flink-core |
#4446 |
— |
✅ Closed (N/A) — entire module removed in #4432; no migration needed |
streampark-flink-shims |
#4447 |
#4461 |
✅ Merged |
streampark-flink-sqlclient |
#4448 |
#4462 |
🔄 PR open, CI green, mergeable |
streampark-flink-packer |
#4449 |
#4463 |
🔄 PR open (stacked on #4462) |
streampark-flink-proxy |
#4450 |
#4464 |
🔄 PR open (stacked on #4463) |
streampark-flink-kubernetes |
#4451 |
— |
⏳ Pending |
streampark-flink-client |
#4452 |
— |
⏳ Pending |
| Stage 3 refactor |
#4453 |
— |
⏳ Pending (after Stages 1–2) |
Scala inventory on dev (post-#4461): ~118 .scala files remaining (down from ~240 baseline). Modules at 0 Scala: streampark-common, streampark-flink-shims. Intentional bridge module: streampark-common-scala-bridge (2 files, retained for downstream Scala interop during transition).
Note on streampark-flink-core: The module no longer exists — it was fully removed in #4432 along with FlinkStreaming / FlinkTable user-dev traits. Equivalent infrastructure (config, SQL runtime, initializers, version contexts) now lives in streampark-flink-shims-base and was migrated in #4461. Issue #4446 has been closed as obsolete.
Goals
Current Inventory (2026-07-29, dev branch)
Updated after #4458 (common) and #4461 (shims) merged. Baseline was ~240 files before migration started.
| Area |
Scala .scala files |
Notes |
streampark-common |
0 |
✅ Migrated in #4458 |
streampark-flink-shims (+ base) |
0 |
✅ Migrated in #4461 |
streampark-flink-sqlclient |
1 |
🔄 PR #4462 ready |
streampark-flink-packer |
34 |
🔄 PR #4463 in review |
streampark-flink-proxy |
1 |
🔄 PR #4464 in review |
streampark-flink-kubernetes |
38 |
Pending (#4451) |
streampark-flink-client |
27 |
Pending (#4452) |
streampark-spark (remaining) |
~15 |
Client + sqlclient (core traits removed in #4432) |
streampark-common-scala-bridge |
2 |
Intentional — Logger/Implicits bridge during transition |
streampark-console |
0 |
Pure Java; consumes Scala JARs |
| Total |
~118 |
Down from ~240 |
Already removed (not in migration scope)
| Module |
PR |
Notes |
streampark-flink-connector (all sub-modules) |
#4432 |
Sink/source wrapper helpers dropped; use Flink native connectors |
streampark-spark-connector (all sub-modules) |
#4432 |
Spark connector wrappers dropped |
streampark-flink-core (entire module) |
#4432 |
Module deleted; FlinkStreaming, FlinkTable, DataStreamExt removed. Core infra moved to streampark-flink-shims-base → migrated in #4461. #4446 closed as N/A. |
streampark-spark-core Scala traits |
#4432 |
SparkStreaming, SparkBatch removed |
Key Scala-specific patterns in use
| Pattern |
Example |
Java replacement strategy |
object singleton facades |
FlinkClient, FlinkShimsProxy, Utils |
final class + static methods, or Spring @Component where appropriate |
trait lifecycle API |
FlinkStreaming, FlinkTable, SparkStreaming |
Abstract Java class or interface + template method (new Java API where needed) |
implicit conversions |
Implicits, EnhancerImplicit, DataStreamExt |
Explicit static helper classes; no implicit magic |
enumeratum enums |
SqlCommandParser command types |
Java enum (migrated in common/shims) |
ClassTag / reflection |
FlinkClient shims dispatch |
Plain Java classes + ClassLoader reflection (already partially used) |
| json4s |
K8s REST JSON parsing |
Jackson (already in dependency tree) |
| ScalaTest |
packer/k8s/client tests |
JUnit 5 + AssertJ (Console standard) |
Execution Plan — Sub-Tasks
The overall plan is delivered in three stages. Stages 1 and 2 are language migration only — rewrite streampark-common / streampark-flink from Scala to Java following Java architecture and idioms, with no behavior changes. These tasks are a good entry point for new contributors; PMC members should provide guidance.
Important: PRs within Stage 1 and Stage 2 are not parallel. Each PR must land sequentially; later PRs depend on the previous one.
Stage 1 — Flink Core
Principle: no logic changes; migrate modules to Java with readable, idiomatic code. Minimal-risk executable task list:
| # |
Module |
Brief role |
Issue |
PR |
Status |
| 1 |
streampark-common |
Shared foundation — utils, config, filesystem, constants; depended on by all modules |
#4445 |
#4458 |
✅ Merged |
| 2 |
streampark-flink-core |
Flink core — job runtime context, environment initialization |
#4446 |
— |
✅ N/A — module removed (#4432), issue closed |
| 3 |
streampark-flink-shims |
Flink multi-version adapter — shims hide API differences across Flink 1.17–1.20 |
#4447 |
#4461 |
✅ Merged |
| 4 |
streampark-flink-sqlclient |
Flink SQL job entry — SqlClient CLI, SQL parse & execute path |
#4448 |
#4462 |
🔄 PR open |
Stage 2 — Job deployment
| # |
Module |
Brief role |
Issue |
PR |
Status |
| 1 |
streampark-flink-packer |
Build & package user jobs into distributable deployable artifacts |
#4449 |
#4463 |
🔄 PR open |
| 2 |
streampark-flink-proxy |
Shims proxy — ChildFirstClassLoader, per-Flink-version isolation and dispatch |
#4450 |
#4464 |
🔄 PR open |
| 3 |
streampark-flink-kubernetes |
Kubernetes integration — deploy, job watchers, ingress, etc. |
#4451 |
— |
⏳ Pending |
| 4 |
streampark-flink-client |
Submit client — Flink job submit / cancel / deploy |
#4452 |
— |
⏳ Pending |
Stage 3 — Architecture upgrade & refactor
Stages 1–2 complete the Scala → Java language conversion. Stage 3 revisits the modules above and performs necessary architectural refactors on that Java baseline. This stage is higher difficulty and should be led by core maintainers (or completed with their direct support).
| # |
Module |
Brief role |
Issue |
PR |
Status |
| 1 |
Stage 3 scope |
Architecture upgrade & refactor on Java baseline (Stage 3) |
#4453 |
— |
⏳ Pending |
Already landed:
Risks & Mitigations
| Risk |
Impact |
Mitigation |
| Breaking user Scala jobs |
High |
Migration guide; clear 3.0 release notes |
| Shims classloader regressions |
High |
Integration tests per Flink version; no change to cache key semantics |
| Mode priority / StatementSet confusion |
High |
Phase 0 tests; explicit SqlSubmissionResult in Phase 5 |
| Large PR review load |
Medium |
One architecture layer per phase (Phases 1–5) |
| Credential leakage in SQL logs |
Medium |
Redaction in Phase 7 only |
Acceptance Criteria
./mvnw clean install -DskipTests succeeds without scala-maven-plugin.
./mvnw clean install full test suite passes (Java tests only).
- Console can submit/cancel Flink & Spark apps on representative deploy modes (YARN, K8s session/application).
- SQL validation and Flink SQL submit work for supported Flink versions.
- Existing Console Flink SQL apps start without user changes; mode priority covered by tests.
- JobGraph and Application submit paths verified (Phase 6).
- No
.scala files under src/main or src/test.
- User migration guide published on streampark.apache.org.
- Each stage/phase independently revertible.
References
Background
StreamPark was originally built with a Scala-first development model: user applications extend
FlinkStreaming/FlinkTable/SparkStreaming/SparkBatchtraits; Flink multi-version support is implemented via Scala shims behindFlinkShimsProxy; and most runtime modules (streampark-common, Flink client/K8s/packer, Spark client) are written in Scala.This creates several long-term costs:
scala-maven-plugin, Scalafmt, Scalastyle, silencer, ScalaTest, and mixed Java/Scala compilation increase CI time and contributor onboarding friction.streampark-console-serviceis Java/Spring Boot but depends heavily on Scala-compiled libraries (HadoopUtils,FlinkClient,FlinkShimsProxy, packer pipelines, etc.).#4432 removed the user-facing dev framework and connector wrappers. Flink SQL jobs now run through
SqlClient→ versionedStreamTableContext/TableContext→FlinkSqlExecutor. Structural refactors on that path must preserve external behavior.This issue tracks the design and execution plan to remove Scala from the StreamPark codebase and safely refactor the Flink SQL submission stack.
Implementation PRs: #4458, #4461 merged; #4462–#4464 in review (stacked)
Depends on: #4409 (JDK 11 baseline ✅), #4432 (dev framework removal ✅)
Parent roadmap: #4410
Community workflow (PMC sync): migrate class-by-class; each new Java class should ship with tests (or document why not). Sub-task issues: #4445 #4446 #4447 #4448 #4449 #4450 #4451 #4452 #4453 — link PRs to the matching row below. Opening a separate GitHub issue per class is optional when you want an isolated review thread.
Progress Update (2026-07-29)
Overall: Stage 1 is ~75% landed on
dev; Stage 2 stacked PRs (#4463, #4464) are in flight.streampark-commonstreampark-flink-corestreampark-flink-shimsstreampark-flink-sqlclientstreampark-flink-packerstreampark-flink-proxystreampark-flink-kubernetesstreampark-flink-clientScala inventory on
dev(post-#4461): ~118.scalafiles remaining (down from ~240 baseline). Modules at 0 Scala:streampark-common,streampark-flink-shims. Intentional bridge module:streampark-common-scala-bridge(2 files, retained for downstream Scala interop during transition).Goals
scala-maven-plugin, Scalafmt/Scalastyle, ScalaTest, silencer,mockito-scala).SqlCliententry or deploy-mode behavior.Current Inventory (2026-07-29,
devbranch).scalafilesstreampark-commonstreampark-flink-shims(+ base)streampark-flink-sqlclientstreampark-flink-packerstreampark-flink-proxystreampark-flink-kubernetesstreampark-flink-clientstreampark-spark(remaining)streampark-common-scala-bridgestreampark-consoleAlready removed (not in migration scope)
streampark-flink-connector(all sub-modules)streampark-spark-connector(all sub-modules)streampark-flink-core(entire module)FlinkStreaming,FlinkTable,DataStreamExtremoved. Core infra moved tostreampark-flink-shims-base→ migrated in #4461. #4446 closed as N/A.streampark-spark-coreScala traitsSparkStreaming,SparkBatchremovedKey Scala-specific patterns in use
objectsingleton facadesFlinkClient,FlinkShimsProxy,Utilsfinal class+ static methods, or Spring@Componentwhere appropriatetraitlifecycle APIFlinkStreaming,FlinkTable,SparkStreamingimplicitconversionsImplicits,EnhancerImplicit,DataStreamExtenumeratumenumsSqlCommandParsercommand typesenum(migrated in common/shims)ClassTag/ reflectionFlinkClientshims dispatchClassLoaderreflection (already partially used)Execution Plan — Sub-Tasks
The overall plan is delivered in three stages. Stages 1 and 2 are language migration only — rewrite
streampark-common/streampark-flinkfrom Scala to Java following Java architecture and idioms, with no behavior changes. These tasks are a good entry point for new contributors; PMC members should provide guidance.Stage 1 — Flink Core
Principle: no logic changes; migrate modules to Java with readable, idiomatic code. Minimal-risk executable task list:
streampark-commonstreampark-flink-coreFlink core — job runtime context, environment initializationstreampark-flink-shimsstreampark-flink-sqlclientSqlClientCLI, SQL parse & execute pathStage 2 — Job deployment
streampark-flink-packerstreampark-flink-proxyChildFirstClassLoader, per-Flink-version isolation and dispatchstreampark-flink-kubernetesstreampark-flink-clientStage 3 — Architecture upgrade & refactor
Stages 1–2 complete the Scala → Java language conversion. Stage 3 revisits the modules above and performs necessary architectural refactors on that Java baseline. This stage is higher difficulty and should be led by core maintainers (or completed with their direct support).
Already landed:
streampark-flink-coremodule ✅${revision}✅streampark-commonScala → Java ✅streampark-flink-shimsScala → Java ✅Risks & Mitigations
SqlSubmissionResultin Phase 5Acceptance Criteria
./mvnw clean install -DskipTestssucceeds withoutscala-maven-plugin../mvnw clean installfull test suite passes (Java tests only)..scalafiles undersrc/mainorsrc/test.References
${revision}: [Build] Switch to 3.0.0-SNAPSHOT using Maven revision property #4425 / [Build] Switch to 3.0.0-SNAPSHOT using Maven revision property #4426 ✅FlinkShimsProxy/ChildFirstClassLoader— high sensitivity (see AGENTS.md)