shangeyao opened a new issue, #4408:
URL: https://github.com/apache/streampark/issues/4408
## 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/connectors, Spark client/connectors) are written in Scala.
This creates several long-term costs:
1. **Build complexity**: `scala-maven-plugin`, Scalafmt, Scalastyle,
silencer, ScalaTest, and mixed Java/Scala compilation increase CI time and
contributor onboarding friction.
2. **Ecosystem alignment**: Apache Flink 2.x removed the Scala DataStream
API; continuing Scala-centric APIs fights upstream direction.
3. **Console alignment**: `streampark-console-service` is Java/Spring Boot
but depends heavily on Scala-compiled libraries (`HadoopUtils`, `FlinkClient`,
`FlinkShimsProxy`, packer pipelines, etc.).
4. **Maintenance multiplier**: Every shims change must be replicated across
**12 Flink version modules** (1.12–1.20, plus future 2.x), most of which are
Scala.
This issue tracks the **design and execution plan** to remove Scala from the
StreamPark codebase.
---
## Goals
- [ ] Eliminate Scala source code from all StreamPark modules (including
tests).
- [ ] Remove Scala from the Maven build toolchain (`scala-maven-plugin`,
Scalafmt/Scalastyle, ScalaTest, silencer, `mockito-scala`).
- [ ] Provide **Java-first public APIs** for user application development
and SQL/streaming lifecycle.
- [ ] Preserve functional parity for Console operations
(submit/cancel/deploy, SQL validation, K8s tracking, packaging).
- [ ] Document migration path and deprecation timeline for existing
Scala-based user jobs.
## Non-Goals (initial phase)
- Rewriting third-party Flink/Spark dependencies that still ship `_2.12`
artifacts (we stop **authoring** Scala, but may still consume Flink's binary
artifacts).
- Changing frontend stack (Vue/TS) — out of scope.
- Big-bang rewrite in a single PR — migration must be phased and CI-green at
each step.
---
## Current Inventory (baseline)
| Area | Scala `.scala` files (approx.) | Notes |
|------|-------------------------------|-------|
| `streampark-common` | 61 (51 main + 10 test) | Utils, config, FS; Java
enums already exist alongside Scala |
| `streampark-flink-connector` | 76 | Sink/source helpers, often Flink Scala
API |
| `streampark-flink-shims` (+ base) | 62 | 12 version modules × ~5 files +
shared base traits |
| `streampark-flink-kubernetes` | 38 | K8s watcher, ingress; uses json4s |
| `streampark-flink-packer` | 34 | Build pipelines |
| `streampark-flink-client` | 27 | `FlinkClient`, deploy/submit clients |
| `streampark-flink-core` | 4 | **Public user API**: `FlinkStreaming`,
`FlinkTable`, `DataStreamExt` |
| `streampark-flink-proxy` | 1 | `FlinkShimsProxy` (classloader isolation) |
| `streampark-flink-sqlclient` | 1 | SQL CLI entry |
| `streampark-spark` (all) | 39 | Core traits, client, connectors, sqlclient
|
| `streampark-console` | **0** | Pure Java; consumes Scala JARs |
| **Total** | **~343** | 22 Scala test files |
### 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 |
| `implicit` conversions | `Implicits`, `EnhancerImplicit`, `DataStreamExt`
| Explicit static helper classes; no implicit magic |
| `enumeratum` enums | `SqlCommandParser` command types | Java `enum`
(already used in `common/enums`) |
| `ClassTag` / reflection | `FlinkClient` shims dispatch | Plain Java
classes + `ClassLoader` reflection (already partially used) |
| json4s | K8s REST JSON parsing | Jackson (already in dependency tree) |
| scalikejdbc | Kafka offset store | JDBC via HikariCP / MyBatis-style thin
wrapper |
| ScalaTest | common/flink tests | JUnit 5 + AssertJ (Console standard) |
### Critical dependency graph
```
streampark-console (Java)
└── streampark-common (Scala) ─────────────────┐
└── streampark-flink-client (Scala) │
└── streampark-flink-proxy / FlinkShimsProxy │
└── streampark-flink-packer (Scala) ├── all Scala today
└── streampark-flink-kubernetes (Scala) │
└── streampark-spark-client (Scala) ───────────┘
User Flink apps
└── streampark-flink-core (Scala traits)
└── Flink Scala DataStream API (removed in Flink 2.x)
```
---
## Proposed Target Architecture
### 1. User development API (breaking change, needs migration guide)
Replace Scala traits with Java lifecycle base classes:
```java
public abstract class FlinkStreamingJob {
protected StreamExecutionEnvironment env;
protected ParameterTool parameter;
public final void main(String[] args) {
init(args);
ready();
handle();
execute();
destroy();
}
protected void ready() {}
protected abstract void handle() throws Exception;
protected void destroy() {}
protected void configure(StreamExecutionEnvironment env, ParameterTool
parameter) {}
}
```
- Package: `org.apache.streampark.flink.core.java` (mirror current `scala`
package layout during transition).
- **Deprecation**: keep Scala traits as thin deprecated wrappers delegating
to Java base for **one major release**, then remove.
- For Flink 1.12–1.20: use **Java DataStream API**
(`org.apache.flink.streaming.api.environment.StreamExecutionEnvironment`) even
if Flink also ships Scala API.
- For Flink 2.x: already Java-only upstream — StreamPark Java API becomes
the canonical path.
Same pattern for `FlinkTable`, `FlinkStreamTable`, `SparkStreaming`,
`SparkBatch`.
### 2. Shims layer refactor
**Problem**: 12 near-identical Scala shims modules; `FlinkShimsProxy` is
Scala `object` with mutable cache.
**Target**:
- Define **Java interfaces** in `streampark-flink-shims-base` (e.g.
`FlinkShimsService`, `FlinkSqlValidator`, `FlinkClusterClient`).
- Each version module implements interfaces in **Java** (5 classes/module →
~60 small Java files, but mechanically similar).
- Rewrite `FlinkShimsProxy` → `FlinkShimsClassLoader` (Java) with unchanged
classloader isolation semantics (ChildFirstClassLoader, per-version cache).
**Do not introduce static state leaking across classloaders.**
- Consider consolidating duplicate shims code via a shared Java abstract
base parameterized by Flink version differences (where API is stable).
### 3. `streampark-common` → Java
Priority order (most Console callers first):
1. `util/`: `Utils`, `HadoopUtils`, `YarnUtils`, `HttpClientUtils`,
`ClassLoaderUtils`, `FileUtils`, …
2. `conf/`: `FlinkVersion`, `SparkVersion`, `CommonConfig`, `ConfigKeys`
wrappers
3. `fs/`: `FsOperator`, `HdfsOperator`, `LfsOperator`
4. Remove `Implicits.scala` — replace call sites with plain Java collections
/ `AutoCloseable` try-with-resources.
`FlinkVersion` already exposes Java-friendly methods via `@BeanProperty` /
explicit getters — migrate to pure Java POJO.
### 4. Flink runtime modules
| Module | Migration notes |
|--------|-----------------|
| `streampark-flink-client` | Convert `SubmitRequest`/`SubmitResponse` beans
to Java records or Lombok `@Data`; `FlinkClient` → Java facade |
| `streampark-flink-kubernetes` | Replace json4s with Jackson; convert
watchers/controllers to Java |
| `streampark-flink-packer` | Pipeline pattern maps cleanly to Java
interfaces |
| `streampark-flink-connector-*` | Largest bulk; many sinks use Flink Scala
`DataStream` — rewrite against Java `DataStream` API |
| `streampark-flink-sqlclient` | Java `main` entry |
### 5. Spark modules (`-Pspark`)
Same strategy as Flink client/core/connectors. Spark still supports Scala
API upstream, but StreamPark should expose Java lifecycle only.
### 6. Build & CI cleanup
Remove from root `pom.xml` and module POMs:
- `scala.version`, `scala-maven-plugin`, `maven-scalastyle-plugin`
- Spotless Scalafmt config (`tools/checkstyle/.scalafmt.conf`)
- `scalatest`, `mockito-scala`, `silencer-plugin`
- `scala-library` / `scala-compiler` dependency management entries
Update `AGENTS.md` coding conventions (Scala section → Java-only).
---
## Phased Execution Plan
### Phase 0 — Design sign-off & compatibility policy (this issue)
- [ ] PMC/committer agreement on breaking API change policy
- [ ] Define deprecation window (proposal: **2 minor releases** for Scala
user API)
- [ ] Publish user migration guide skeleton in docs
### Phase 1 — Foundation (`streampark-common` → Java)
- [ ] Convert `util/*` and `conf/*` to Java with parity tests (JUnit 5)
- [ ] Keep Scala modules delegating to Java via thin wrappers (temporary)
**or** use dual compilation bridge
- [ ] CI green; Console integration tests pass
**Estimated scope**: ~60 files, **1–2 PRs**
### Phase 2 — Proxy & client facades
- [ ] `FlinkShimsProxy` → Java
- [ ] `FlinkClient` / request-response beans → Java
- [ ] `SparkShimsProxy`, `SparkClient` → Java
- [ ] Console services unchanged at source level (same public Java API)
**Estimated scope**: ~30 files, **2–3 PRs**
### Phase 3 — Shims base + one pilot version (e.g. 1.20)
- [ ] Java interfaces in shims-base
- [ ] Migrate `streampark-flink-shims_flink-1.20` to Java
- [ ] Validate submit/cancel/SQL verify against 1.20 cluster
- [ ] Document mechanical migration template for remaining versions
**Estimated scope**: **1 PR per Flink version** (11 remaining) — can
parallelize
### Phase 4 — User-facing `streampark-flink-core` / `streampark-spark-core`
- [ ] Introduce Java lifecycle base classes
- [ ] Deprecate Scala traits (annotation + docs)
- [ ] Update archetypes/examples
**Breaking change release note required**
### Phase 5 — K8s, packer, connectors
- [ ] `streampark-flink-kubernetes` (json4s → Jackson)
- [ ] `streampark-flink-packer`
- [ ] `streampark-flink-connector-*` (largest effort; batch by connector)
- [ ] Spark connectors + sqlclient
**Estimated scope**: ~150 files, **multiple PRs**
### Phase 6 — Remove Scala completely
- [ ] Delete remaining `.scala` files and Scala test sources
- [ ] Remove Scala build plugins/deps
- [ ] Remove Scalafmt/Scalastyle from Spotless/CI
- [ ] Final grep: zero `.scala` in repo
---
## Risks & Mitigations
| Risk | Impact | Mitigation |
|------|--------|------------|
| Breaking user Scala jobs | High | Deprecation period; migration guide;
compat module optional |
| Shims classloader regressions | High | Dedicated integration tests per
Flink version; no change to cache key semantics |
| Connector rewrite bugs | Medium | Port tests first; one connector per PR |
| Large PR fatigue | Medium | Strict phase gates; module-by-module |
| Flink 1.12–1.19 Java API gaps | Medium | Use Flink Java DataStream API;
shims hide version diffs |
| json4s / scalikejdbc removal | Low | Jackson + JDBC already available |
---
## Acceptance Criteria
1. `./mvnw clean install -DskipTests` succeeds **without**
`scala-maven-plugin`.
2. `./mvnw clean install` full test suite passes (Java tests only).
3. Console can submit/cancel Flink & Spark apps on representative deploy
modes (YARN, K8s session/application).
4. SQL validation works for supported Flink versions.
5. No `.scala` files under `src/main` or `src/test`.
6. User migration guide published on streampark.apache.org.
---
## Suggested Sub-Issues (to be created after sign-off)
1. `[Common] Migrate streampark-common utilities to Java`
2. `[Flink] Rewrite FlinkShimsProxy and FlinkClient in Java`
3. `[Flink] Java shims template + Flink 1.20 pilot`
4. `[Flink] Migrate remaining Flink shims versions (1.12–1.19, 2.x)`
5. `[Flink] Java user API for FlinkStreaming/FlinkTable + deprecation`
6. `[Flink] Migrate kubernetes module (json4s → Jackson)`
7. `[Flink] Migrate packer module to Java`
8. `[Flink] Migrate connector modules to Java (track per connector)`
9. `[Spark] Migrate Spark modules to Java`
10. `[Build] Remove Scala toolchain and update AGENTS.md`
---
## Open Questions
1. **Deprecation timeline**: one or two minor releases for Scala user API?
2. **Flink version support window**: migrate all 1.12–1.20 shims, or drop
EOL versions first to reduce work?
3. **Optional compat artifact**: ship `streampark-flink-core-scala`
deprecated module for one release?
4. **Spark profile**: migrate Spark in same epic or separate track?
5. **JDK baseline**: stay on JDK 8 for Console, or raise baseline as part of
this effort?
---
## References
- Flink 2.x removes Scala DataStream API (StreamPark Flink 2.x work should
be Java-first)
- `FlinkShimsProxy` / `ChildFirstClassLoader` — high sensitivity (see
AGENTS.md)
- `FlinkStreaming` lifecycle contract — must preserve execution order
(`main` → `init` → `ready` → `handle` → `destroy`)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]