This is an automated email from the ASF dual-hosted git repository.
wusheng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-graalvm-distro.git
The following commit(s) were added to refs/heads/main by this push:
new faa12dd Update documentation: remove step/phase prefixes, reflect
current state
faa12dd is described below
commit faa12ddfbb28c4cee0dca3d8d41408fae6d14995
Author: Wu Sheng <[email protected]>
AuthorDate: Wed Feb 25 08:55:08 2026 +0800
Update documentation: remove step/phase prefixes, reflect current state
All immigration work is complete. Remove progress-tracking prefixes
(Phase N, Step N, Challenge N, DONE/COMPLETE/SOLVED suffixes, checkboxes)
and restructure around the compilation workflow.
Also update README with native/Docker commands, project structure,
and refresh all immigration docs to match current code paths.
---
CLAUDE.md | 31 ++++++--
CONFIG-INIT-IMMIGRATION.md | 6 +-
DISTRO-POLICY.md | 189 ++++++++++++++++++---------------------------
LAL-IMMIGRATION.md | 17 ++--
MAL-IMMIGRATION.md | 77 +++++++++---------
OAL-IMMIGRATION.md | 46 +++++------
README.md | 38 +++++++--
7 files changed, 195 insertions(+), 209 deletions(-)
diff --git a/CLAUDE.md b/CLAUDE.md
index 8dffa54..ce04263 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -2,9 +2,13 @@
## Project Structure
- `skywalking/` — Git submodule of `apache/skywalking.git`. **Do not modify
directly.** All SkyWalking source changes go through upstream PRs.
-- `build-tools/precompiler/` — Build-time precompiler: runs OAL + MAL + LAL
engines at Maven compile time, exports `.class` files and manifests into
`precompiler-*-generated.jar`.
-- `oap-graalvm-server/` — GraalVM-ready OAP server module with same-FQCN
replacement classes and comprehensive test suites.
-- `DISTRO-POLICY.md` — Current build plan (draft/temporary, subject to change).
+- `build-tools/precompiler/` — Build-time precompiler: runs OAL + MAL + LAL
engines at Maven compile time, exports `.class` files, manifests, and
auto-generated `reflect-config.json` into `precompiler-*-generated.jar`.
+- `build-tools/config-generator/` — Build-time config code generator: scans
`ModuleConfig` subclasses and generates `YamlConfigLoaderUtils` replacement.
+- `oap-libs-for-graalvm/` — Per-JAR repackaged modules using
`maven-shade-plugin` for same-FQCN class replacements.
+- `oap-graalvm-server/` — GraalVM-ready OAP server module (JVM distro) with
same-FQCN replacement classes and comprehensive test suites.
+- `oap-graalvm-native/` — Native image module: `native-maven-plugin`
configuration, native-specific `log4j2.xml`, `log4j2-reflect-config.json`, and
native distribution assembly.
+- `docker/` — `Dockerfile.native` (runtime image) and `docker-compose.yml`
(BanyanDB + OAP native).
+- `DISTRO-POLICY.md` — Build plan with phase tracking and module selection.
- Root-level Maven + Makefile — Orchestrates building on top of the submodule.
## Key Principles
@@ -15,11 +19,14 @@
## Technical Notes
- **OAL engine**: Generates metrics classes via Javassist at startup. For
native image, run OAL engine at build time, export `.class` files. OAL uses
ANTLR4 + FreeMarker + Javassist (not Groovy).
-- **MAL precompiler**: Compiles all 71 MAL YAML rule files
(meter-analyzer-config, otel-rules, log-mal-rules, envoy-metrics-rules,
telegraf-rules, zabbix-rules) into 1250 Groovy scripts at build time. Produces
`META-INF/mal-groovy-manifest.txt` (script→class mapping) and
`META-INF/mal-groovy-expression-hashes.txt` (expression SHA-256 hashes for
combination pattern resolution).
+- **MAL transpiler**: Transpiles all 71 MAL YAML rule files (1250+
expressions) from Groovy AST to pure Java `MalExpression` classes at build
time. Zero Groovy at runtime. Produces `META-INF/mal-expressions.txt` and
`META-INF/mal-groovy-expression-hashes.txt` (SHA-256 hashes for combination
pattern resolution).
+- **LAL transpiler**: Transpiles 10 LAL scripts (6 unique) from Groovy AST to
pure Java `LalExpression` classes. SHA-256 deduplication for identical DSL
bodies.
- **Combination pattern**: Multiple YAML files from different data sources
(otel, telegraf, zabbix) may define metrics with the same name. The precompiler
assigns deterministic suffixes (`_1`, `_2`, etc.) and tracks expression hashes
for unambiguous resolution.
-- **Same-FQCN replacement**: Classes in `oap-graalvm-server/src/main/java/`
with the same fully-qualified class name as upstream classes override them via
Maven classpath ordering. Used for `DSL.java`, `LogFilterExpression.java`, etc.
+- **Same-FQCN replacement**: Classes in
`oap-libs-for-graalvm/*/src/main/java/` with the same fully-qualified class
name as upstream classes are repackaged via `maven-shade-plugin` (original
`.class` excluded). Used for `DSL.java`, `SampleFamily.java`,
`MeterSystem.java`, etc.
- **Classpath scanning**: Guava `ClassPath.from()` used in multiple places.
Run at build-time pre-compilation as verification gate, export static class
index.
-- **Config loading**: `YamlConfigLoaderUtils.copyProperties()` replaced with
same-FQCN version that uses Lombok setters + VarHandle instead of
`Field.setAccessible()`. See
[CONFIG-INIT-IMMIGRATION.md](CONFIG-INIT-IMMIGRATION.md).
+- **Config loading**: `YamlConfigLoaderUtils.copyProperties()` replaced with
same-FQCN version that uses Lombok setters instead of `Field.setAccessible()`.
See [CONFIG-INIT-IMMIGRATION.md](CONFIG-INIT-IMMIGRATION.md).
+- **Reflection metadata**: Precompiler auto-generates `reflect-config.json` by
scanning Armeria HTTP handlers, GraphQL resolvers/types, config POJOs, and
OAL/MAL/LAL manifests. `log4j2-reflect-config.json` is manually maintained for
Log4j2 plugin classes.
+- **Native image**: `oap-graalvm-native` uses `native-maven-plugin` with
`-Pnative` profile. Console-only `log4j2.xml` avoids RollingFile reflection
chain. ~203MB binary, boots to full module init.
## Test Suites
- **MAL**: 71 YAML files covered by 73 test classes (1,281 assertions). See
`oap-graalvm-server/src/test/CLAUDE.md` for test generation instructions and
`oap-graalvm-server/src/test/MAL-COVERAGE.md` for coverage tracking.
@@ -37,6 +44,18 @@ JAVA_HOME=/Users/wusheng/.sdkman/candidates/java/25-graal
mvn -pl build-tools/pr
# Run MAL tests only
JAVA_HOME=/Users/wusheng/.sdkman/candidates/java/25-graal mvn -pl
oap-graalvm-server test
+
+# Native image (requires GraalVM with native-image)
+JAVA_HOME=/Users/wusheng/.sdkman/candidates/java/25-graal make native-image
+
+# Native image for Docker on macOS (cross-compiles via Docker container)
+make native-image-macos
+
+# Package native binary into Docker image
+make docker-native
+
+# Run with docker-compose (BanyanDB + OAP native)
+docker compose -f docker/docker-compose.yml up
```
## Git Commit Rules
diff --git a/CONFIG-INIT-IMMIGRATION.md b/CONFIG-INIT-IMMIGRATION.md
index 49d15d0..3b96b61 100644
--- a/CONFIG-INIT-IMMIGRATION.md
+++ b/CONFIG-INIT-IMMIGRATION.md
@@ -1,4 +1,4 @@
-# Phase 2: Config Initialization Immigration — Eliminate Reflection in Config
Loading
+# Config Initialization — Eliminate Reflection in Config Loading
## Context
@@ -39,7 +39,7 @@ Generate a replacement `YamlConfigLoaderUtils.java` with the
same FQCN
dispatches by config object type and sets fields directly — no
`Field.setAccessible()`, no `getDeclaredField()` scan.
-This is the 8th same-FQCN replacement class in the distro.
+This is one of 23 same-FQCN replacement classes in the distro (see
DISTRO-POLICY.md for full list).
### Field Access Strategy (per field)
@@ -127,7 +127,7 @@ config classes with `@Setter` added. Original upstream JARs
are forced to
### Output
-
`oap-graalvm-server/src/main/java/org/apache/skywalking/oap/server/library/util/YamlConfigLoaderUtils.java`
- (same-FQCN replacement — 8th replacement class)
+ (same-FQCN replacement)
### Running the generator
```bash
diff --git a/DISTRO-POLICY.md b/DISTRO-POLICY.md
index 3362007..c192373 100644
--- a/DISTRO-POLICY.md
+++ b/DISTRO-POLICY.md
@@ -37,7 +37,7 @@ Build and package Apache SkyWalking OAP server as a GraalVM
native image on JDK
---
-## Challenge 1: OAL Runtime Class Generation (Javassist) — SOLVED
+## OAL Runtime Class Generation (Javassist)
### What Happens
OAL V2 generates metrics/builder/dispatcher classes at startup via Javassist
(`ClassPool.makeClass()` → `CtClass.toClass()`). Already has
`writeGeneratedFile()` for debug export.
@@ -57,7 +57,7 @@ All `.oal` scripts are known. Run OAL engine at build time,
export `.class` file
---
-## Challenge 2: MAL and LAL (Groovy + Javassist) — SOLVED
+## MAL and LAL (Groovy + Javassist)
### What Happens
- MAL uses `GroovyShell` + `DelegatingScript` for meter rule expressions
(~1250 rules across 71 YAML files). Also, `MeterSystem.create()` uses Javassist
to dynamically generate one meter subclass per metric rule.
@@ -78,14 +78,14 @@ Run full MAL/LAL initialization at build time via
`build-tools/precompiler` (uni
- **Same-FQCN replacements**: `DSL.java` (MAL), `DSL.java` (LAL),
`FilterExpression.java`, `MeterSystem.java`, `Expression.java`,
`SampleFamily.java` — all use pure Java, no Groovy.
- **Comparison test suite**: 73 MAL test classes (1281 assertions) + 5 LAL
test classes (19 assertions) covering all 79 YAML files. Tests require data
flow through full pipeline (no vacuous agreements). Dual-path: fresh Groovy
compilation (Path A) vs transpiled Java (Path B).
-### Groovy Elimination: COMPLETE
+### Groovy Elimination
- MAL: `MalExpression` interface replaces `DelegatingScript`. `SampleFamily`
uses Java functional interfaces (`TagFunction`, `SampleFilter`,
`ForEachFunction`, `DecorateFunction`, `PropertiesExtractor`) instead of
`groovy.lang.Closure`.
- LAL: `LalExpression` interface replaces `DelegatingScript`. Spec classes
have `Consumer` overloads.
- No `groovy.lang.Closure` in any production source code. Groovy is test-only
dependency.
---
-## Challenge 3: Classpath Scanning (Guava ClassPath) — SOLVED
+## Classpath Scanning (Guava ClassPath)
### What Happens
`ClassPath.from()` used in `SourceReceiverImpl.scan()`, `AnnotationScan`,
`MeterSystem`, `DefaultMetricsFunctionRegistry`, `FilterMatchers`,
`MetricsHolder`.
@@ -97,7 +97,7 @@ Run full MAL/LAL initialization at build time via
`build-tools/precompiler` (uni
---
-## Challenge 4: Module System & Configuration — SOLVED
+## Module System & Configuration
### Current Behavior
`ModuleManager` uses `ServiceLoader` (SPI). `application.yml` selects
providers. Config loaded via reflection (`Field.setAccessible` + `field.set` in
`YamlConfigLoaderUtils.copyProperties`).
@@ -119,7 +119,7 @@ Run full MAL/LAL initialization at build time via
`build-tools/precompiler` (uni
---
-## Challenge 5: Same-FQCN Packaging — SOLVED (Repackaged Modules)
+## Same-FQCN Packaging (Repackaged Modules)
### Problem
@@ -175,17 +175,16 @@ To add a new same-FQCN replacement:
---
-## Challenge 6: Additional GraalVM Risks
+## Additional GraalVM Risks
-| Risk | Mitigation |
-|------|------------|
-| **Reflection** (annotations, OAL enricher — not config loading) | Captured
during pre-compilation; `reflect-config.json`. Config loading uses generated
code (see [CONFIG-INIT-IMMIGRATION.md](CONFIG-INIT-IMMIGRATION.md)), no
reflection. |
-| **gRPC 1.70.0 / Netty 4.2.9** | GraalVM reachability metadata repo, Netty
substitutions |
-| **Resource loading** (`ResourceUtils`, config files) |
`resource-config.json` via tracing agent |
-| **Log4j2** | GraalVM metadata, disable JNDI |
-| **Kafka client** (for Kafka fetcher) | Known GraalVM support, may need
config |
-| **ElasticSearch client** (not used, BanyanDB selected) | N/A for now |
-| **Kubernetes client 6.7.1** (for cluster + config) | Has GraalVM support,
may need config |
+| Risk | Status | Mitigation |
+|------|--------|------------|
+| **Reflection** (annotations, OAL enricher, HTTP handlers, GraphQL types) |
SOLVED | Auto-generated by precompiler from manifests;
`log4j2-reflect-config.json` for Log4j2 plugins |
+| **gRPC / Netty / Armeria** | SOLVED | GraalVM reachability metadata repo
handles these automatically |
+| **Resource loading** (`ResourceUtils`, config files) | SOLVED |
`resource-config.json` via tracing agent |
+| **Log4j2** | SOLVED | Console-only `log4j2.xml` avoids RollingFile
reflection chain; Log4j2 plugin classes in `log4j2-reflect-config.json` |
+| **Kafka client** (for Kafka fetcher) | Untested | Known GraalVM support, may
need config |
+| **Kubernetes client 6.7.1** (for cluster + config) | Untested | Has GraalVM
support, may need config at runtime |
---
@@ -255,103 +254,69 @@ keys) that replacement loader classes use instead of
filesystem YAML access.
---
-## Proposed Phases
-
-### Phase 1: Build System Setup — COMPLETE
-- [x] Set up Maven + Makefile in this repo
-- [x] Build skywalking submodule as a dependency
-- [x] Set up GraalVM JDK 25 in CI (`.github/workflows/ci.yml`)
-- [x] Create a JVM-mode starter with fixed module wiring (`FixedModuleManager`
+ `GraalVMOAPServerStartUp`)
-- [x] Simplified config file for selected modules (`application.yml`)
-
-### Phase 2: Build-Time Pre-Compilation & Verification — COMPLETE
-
-**OAL immigration — COMPLETE:**
-- [x] OAL engine → export `.class` files (9 defines, ~620 metrics, ~620
builders, ~45 dispatchers)
-- [x] Classpath scanning → export class index (7 annotation/interface
manifests including MeterFunction)
-- [x] Runtime registration from manifests (3 same-FQCN replacement classes:
`OALEngineLoaderService`, `AnnotationScan`, `SourceReceiverImpl`)
-- [x] Verification tests (`PrecompilerTest`, `PrecompiledRegistrationTest`)
-
-**MAL immigration — COMPLETE:**
-- [x] Unified precompiler (`build-tools/precompiler`): replaces separate
`oal-exporter` and `mal-compiler`
-- [x] MAL Groovy pre-compilation: 71 YAML files → 1250 Groovy scripts + 1209
Javassist meter classes
-- [x] Combination pattern support: deterministic suffixes + expression hash
tracking for cross-source metric deduplication
-- [x] Same-FQCN replacements: `DSL.java` (MAL), `DSL.java` (LAL),
`FilterExpression.java`, `MeterSystem.java`
-- [x] Comparison test suite: 73 test classes, 1281 assertions (all 71 YAML
files, 100% coverage)
-- [x] SHA-256 staleness detection for submodule YAML drift
-- [x] `MeterSystem` classpath scan eliminated via manifest
-
-**LAL immigration — COMPLETE:**
-- [x] LAL Groovy pre-compilation: 8 YAML files → 10 rules → 6 unique
pre-compiled classes (`@CompileStatic`)
-- [x] Same-FQCN replacement: `DSL.java` (LAL) loads pre-compiled scripts via
SHA-256 hash lookup
-- [x] Comparison test suite: 5 test classes, 19 assertions (all 8 YAML files,
100% branch coverage)
-
-**Config initialization — COMPLETE:**
-- [x] `ConfigInitializerGenerator` build tool scans all provider config
classes, generates same-FQCN `YamlConfigLoaderUtils` replacement
-- [x] Generated class uses Lombok setters, VarHandle, and getter+clear+addAll
— zero `Field.setAccessible` at runtime
-- [x] Reflective fallback for unknown config types (safety net)
-
-**Config data serialization — COMPLETE:**
-- [x] Precompiler serializes parsed config POJOs to
`META-INF/config-data/*.json` (7 JSON files)
-- [x] 3 same-FQCN replacement loaders: `MeterConfigs` (meter-analyzer-config),
`Rules` (otel-rules, envoy-metrics-rules, telegraf-rules, log-mal-rules),
`LALConfigs` (lal)
-- [x] Replacement loaders deserialize from JSON instead of filesystem YAML,
with glob matching for enabled rules
-
-**Module system — COMPLETE:**
-- [x] `library-module-for-graalvm`: `ModuleDefine` replacement with direct
`prepare()` overload (bypasses ServiceLoader)
-- [x] `FixedModuleManager` simplified: calls `module.prepare(manager,
provider, config, params)` directly
-- [x] `GraalVMOAPServerStartUp`: `configuration.has()` guards for 6 optional
modules (receiver-zabbix, receiver-zipkin, kafka-fetcher, cilium-fetcher,
query-zipkin, exporter)
-
-**Distro resource packaging — COMPLETE:**
-- [x] Identified all 236 upstream resource files: 146 runtime files → distro
`config/`, 89 pre-compiled files → JARs
-- [x] Assembly descriptor (`distribution.xml`) packages runtime config files
from upstream
-- [x] Pre-compiled OAL/MAL/LAL files excluded from distro (not needed at
runtime)
-
-**JVM boot verification — COMPLETE:**
-- [x] Full boot with BanyanDB storage: 38 modules started (6 optional modules
disabled by default)
-- [x] Pre-compiled assets loaded: 620 OAL metrics + 45 dispatchers, 1250 MAL
scripts, 29 filter scripts, 7 LAL scripts
-- [x] Config data loaded from JSON: 9 meter configs, 55 otel rules, 2 envoy
rules, 1 telegraf rule, 1 log-mal rule, 8 LAL configs
-- [x] HTTP endpoints: gRPC :11800, HTTP :12800, Firehose :12801, PromQL :9090,
LogQL :3100, Prometheus :1234
-- [x] Debug logging for per-script MAL/LAL/filter loading (`[count/total]:
metricName`) for e2e verification
-- [x] Dependency versions centralized in root `pom.xml`
-
-### Phase 3: Native Image Build
-
-**Groovy elimination — COMPLETE:**
-- [x] MAL-to-Java transpiler: 1250+ expressions → pure Java `MalExpression`
(no Groovy MOP/ExpandoMetaClass)
-- [x] LAL-to-Java transpiler: 10 scripts → pure Java `LalExpression` (no
DelegatingScript)
-- [x] `SampleFamily` Closure parameters → Java functional interfaces (zero
`groovy.lang.Closure` in production)
-- [x] Groovy stubs module for class loading (no `org.codehaus.groovy.*`)
-- [x] Resolve HierarchyDefinitionService Groovy blocker (same-FQCN replacement
with Java-backed closures)
-- [x] Test quality: 1303 tests require actual data flow (no vacuous
empty-result agreements)
-
-**Groovy runtime removal — COMPLETE:**
-- [x] Wire groovy-stubs as runtime dependency, exclude real Groovy from
runtime classpath
-- [x] Real Groovy (`groovy-5.0.3.jar`) moved to test-only scope;
`groovy-stubs-1.0.0-SNAPSHOT.jar` on runtime classpath
-- [x] JVM distro `libs/` verified: only groovy-stubs, no real Groovy JAR
-
-**Native image build — TODO:**
-- [ ] `native-image-maven-plugin` configuration in `oap-graalvm-native`
-- [ ] Run tracing agent to capture reflection/resource/JNI metadata
-- [ ] `reflect-config.json` for pre-compiled classes (OAL, MAL, LAL, meter
classes — generate from manifests)
-- [ ] `resource-config.json` for runtime config files loaded via
`ResourceUtils.read()`
-- [ ] Configure gRPC/Netty/Protobuf for native image
-- [ ] GraalVM Feature class for SkyWalking-specific registrations
-- [ ] Verify OTEL and Envoy ServiceLoader SPI work in native image (GraalVM
supports META-INF/services natively)
-- [ ] Get OAP server booting as native image with BanyanDB
-
-### Phase 4: Harden & Test
-- [ ] Verify all receiver plugins work
-- [ ] Verify all query APIs work
-- [ ] Verify cluster mode (K8s)
-- [ ] Verify alarm module
-- [ ] Performance benchmarking vs JVM
-- [ ] CI: automated native-image build + smoke tests
+## Build Workflow
+
+### Build System
+- Maven + Makefile orchestrates building on top of the skywalking submodule
+- GraalVM JDK 25 in CI (`.github/workflows/ci.yml`)
+- JVM-mode starter with fixed module wiring (`FixedModuleManager` +
`GraalVMOAPServerStartUp`)
+- Simplified config file for selected modules (`application.yml`)
+
+### Build-Time Pre-Compilation
+
+**OAL**: OAL engine exports `.class` files (9 defines, ~620 metrics, ~620
builders, ~45 dispatchers). 7 annotation/interface manifests. 3 same-FQCN
replacement classes (`OALEngineLoaderService`, `AnnotationScan`,
`SourceReceiverImpl`).
+
+**MAL**: Unified precompiler (`build-tools/precompiler`) processes 71 YAML
files → 1250 expressions transpiled to pure Java `MalExpression` + 1209
Javassist meter classes. Combination pattern with deterministic suffixes +
expression hash tracking. Same-FQCN replacements: `DSL.java`,
`FilterExpression.java`, `MeterSystem.java`, `Expression.java`,
`SampleFamily.java`. 73 comparison test classes, 1281 assertions (100% YAML
coverage).
+
+**LAL**: 8 YAML files → 10 rules → 6 unique transpiled Java `LalExpression`
classes. Same-FQCN `DSL.java` loads via SHA-256 hash lookup. 5 comparison test
classes, 19 assertions (100% branch coverage).
+
+**Config initialization**: `ConfigInitializerGenerator` generates same-FQCN
`YamlConfigLoaderUtils` using Lombok setters — zero `Field.setAccessible` at
runtime.
+
+**Config data serialization**: Precompiler serializes parsed config POJOs to
`META-INF/config-data/*.json` (7 JSON files). 3 same-FQCN replacement loaders
(`MeterConfigs`, `Rules`, `LALConfigs`) deserialize from JSON instead of
filesystem YAML.
+
+**Module system**: `ModuleDefine` replacement with direct `prepare()` overload
(bypasses ServiceLoader). `GraalVMOAPServerStartUp` with `configuration.has()`
guards for 6 optional modules.
+
+**Distro resource packaging**: 146 runtime files → distro `config/`, 89
pre-compiled files → JARs. Assembly descriptor (`distribution.xml`) packages
runtime config files from upstream.
+
+### Groovy Elimination
+
+- MAL-to-Java transpiler: 1250+ expressions → pure Java `MalExpression` (no
Groovy MOP/ExpandoMetaClass)
+- LAL-to-Java transpiler: 10 scripts → pure Java `LalExpression` (no
DelegatingScript)
+- `SampleFamily` Closure parameters → Java functional interfaces (zero
`groovy.lang.Closure` in production)
+- Groovy stubs module for class loading (no `org.codehaus.groovy.*`)
+- HierarchyDefinitionService: same-FQCN replacement with Java-backed closures
+- Real Groovy (`groovy-5.0.3.jar`) is test-only;
`groovy-stubs-1.0.0-SNAPSHOT.jar` on runtime classpath
+- 1303 tests require actual data flow (no vacuous empty-result agreements)
+
+### Native Image Build
+
+- `native-maven-plugin` (GraalVM buildtools 0.10.4) in `oap-graalvm-native`
with `-Pnative` profile
+- `reflect-config.json` auto-generated by precompiler from manifests (OAL,
MAL, LAL, meter, HTTP handlers, GraphQL types)
+- `log4j2-reflect-config.json` for Log4j2 plugin classes; console-only
`log4j2.xml` with `SW_LOG_LEVEL` env var
+- gRPC/Netty/Protobuf/Armeria via GraalVM reachability metadata repository
+- Auto-scanned reflection metadata: Armeria HTTP handlers (~19), GraphQL
resolvers (~32), GraphQL types (~182), config POJOs (8)
+- Native binary: ~203MB, boots to full module init with all HTTP endpoints
functional
+
+### Native Distro Packaging
+
+- Assembly descriptor (`native-distribution.xml`) packages native binary +
config files
+- `Dockerfile.native` packages native distro into `debian:bookworm-slim`
+- `docker-compose.yml` with BanyanDB + OAP native services
+- CI pipeline: multi-arch native build (amd64 + arm64) with Docker manifest
push to GHCR
+
+### Remaining Verification
+- Verify all receiver plugins work (gRPC + HTTP endpoints)
+- Verify all query APIs work (GraphQL, PromQL, LogQL, Zipkin)
+- Verify cluster mode (K8s)
+- Verify alarm module
+- Performance benchmarking vs JVM
---
## Upstream Changes Tracker
-- [x] OAL engine: build-time class export works via existing debug API (no
upstream change needed)
-- [x] MAL: No upstream changes needed — transpiled to pure Java, bypasses
Groovy entirely
-- [x] LAL: No upstream changes needed — transpiled to pure Java, bypasses
Groovy entirely
-- [x] Dynamic Groovy MOP: RESOLVED — transpiled to pure Java, no
ExpandoMetaClass/MOP at runtime
-- [ ] Other findings during implementation
+
+No upstream changes needed. All GraalVM incompatibilities are resolved in this
distro via same-FQCN replacement and build-time pre-compilation:
+- OAL: build-time class export works via existing debug API
+- MAL: transpiled to pure Java, bypasses Groovy entirely
+- LAL: transpiled to pure Java, bypasses Groovy entirely
+- Dynamic Groovy MOP: transpiled to pure Java, no ExpandoMetaClass/MOP at
runtime
diff --git a/LAL-IMMIGRATION.md b/LAL-IMMIGRATION.md
index 8f91206..d22704f 100644
--- a/LAL-IMMIGRATION.md
+++ b/LAL-IMMIGRATION.md
@@ -233,9 +233,7 @@ Expected: 19 comparison tests across 5 test classes, all
passing.
---
-# Phase 3: Pure Java LAL Transpiler — COMPLETE
-
-## Summary
+## Pure Java LAL Transpiler
LAL transpilation is complete. All 10 LAL scripts (6 unique after SHA-256
dedup)
are transpiled from Groovy AST to pure Java source at build time, compiled to
@@ -346,12 +344,9 @@ public class LalExpr_0 implements LalExpression {
---
-## Remaining: Groovy Runtime Removal
-
-The groovy-stubs module exists but is not yet wired as a Groovy replacement on
-the runtime classpath. Real Groovy (`groovy-5.0.3.jar`) is still in the distro.
-Removing it requires:
+## Groovy Runtime Removal
-1. Add `groovy-stubs` as runtime dependency in `oap-graalvm-native/pom.xml`
-2. Exclude real Groovy from runtime dependencies (keep as test-only)
-3. Verify native-image build without `org.codehaus.groovy.*` on classpath
+- `groovy-stubs` wired as runtime dependency
+- Real Groovy (`groovy-5.0.3.jar`) moved to test-only scope
+- Native image builds and boots without `org.codehaus.groovy.*` on classpath
+- `GroovyIndyInterfaceFeature` stays dormant (no `org.codehaus.groovy`
packages)
diff --git a/MAL-IMMIGRATION.md b/MAL-IMMIGRATION.md
index 99ae638..5506e39 100644
--- a/MAL-IMMIGRATION.md
+++ b/MAL-IMMIGRATION.md
@@ -37,7 +37,7 @@ Each MAL metric rule generates one Groovy script + one
Javassist dynamic meter c
---
-## Step 1: MeterFunction Manifest + Same-FQCN MeterSystem
+## MeterFunction Manifest + Same-FQCN MeterSystem
### Problem
@@ -97,19 +97,17 @@ public MeterSystem(ModuleManager manager) {
}
```
-At this step, `create()` still uses Javassist — this is fine for JVM mode.
Step 2 eliminates it.
-
---
-## Step 2: Build-Time MAL/LAL Pre-Compilation + MeterSystem Class Generation
+## Build-Time MAL/LAL Pre-Compilation + MeterSystem Class Generation
-**Module**: `build-tools/mal-compiler` (skeleton exists)
+**Module**: `build-tools/precompiler` (unified tool)
### MALCompiler.java — main build tool
The tool executes the full initialization pipeline at build time:
-#### Phase A: Initialize infrastructure
+#### Initialize infrastructure
```java
// 1. Initialize scope registry (same as OALClassExporter)
@@ -122,7 +120,7 @@ scopeScan.scan();
ExportingMeterSystem meterSystem = new ExportingMeterSystem(outputDir);
```
-#### Phase B: Load and compile all MAL rules
+#### Load and compile all MAL rules
```java
// 3. Agent meter rules (meter-analyzer-config/)
@@ -144,7 +142,7 @@ for (Rule rule : logMalRules) {
}
```
-#### Phase C: Load and compile all LAL rules
+#### Load and compile all LAL rules
```java
// 6. LAL rules (lal/)
@@ -154,7 +152,7 @@ for (LALConfig config : flattenedConfigs) {
}
```
-#### Phase D: Export bytecode + write manifests
+#### Export bytecode + write manifests
The tool intercepts both Groovy and Javassist class generation to capture
bytecode:
@@ -299,12 +297,7 @@ MAL expressions rely on three dynamic Groovy features:
**Approach**: Pre-compile using standard dynamic Groovy (same
`CompilerConfiguration` as upstream — `DelegatingScript` base class,
`SecureASTCustomizer`, `ImportCustomizer`). The compiled `.class` files contain
the same bytecode that `GroovyShell.parse()` would produce. At runtime,
`Class.forName()` + `newInstance()` loads the pre-compiled script, and
`Expression.empower()` sets up the delegate and `ExpandoMetaClass`.
-**GraalVM native image risk** (Phase 3 concern): Dynamic Groovy compiled
classes use `invokedynamic` and Groovy's MOP (Meta-Object Protocol) for method
resolution. In native image, this may need:
-- `reflect-config.json` for all compiled script classes
-- Groovy MOP runtime classes registered for reachability
-- If `ExpandoMetaClass` does not work in native image: fallback to upstream
DSL changes (replace operator overloading with explicit
`SampleFamily.multiply(100, sf)` calls)
-
-Phase 2 focuses on JVM mode — pre-compilation for startup speed. Phase 3
addresses native image compatibility.
+**Native image solution**: Dynamic Groovy was eliminated entirely via the
MAL-to-Java transpiler (see below). All MAL expressions are transpiled to pure
Java at build time — no Groovy MOP, no `ExpandoMetaClass`, no `invokedynamic`
at runtime.
### LAL Groovy: Already @CompileStatic
@@ -312,7 +305,7 @@ LAL already uses `@CompileStatic` with
`LALPrecompiledExtension` for type checki
---
-## Step 3: Verification Tests
+## Verification Tests
### MALCompilerTest (in `build-tools/mal-compiler/src/test/`)
@@ -440,28 +433,28 @@ All replacements are repackaged into their respective
`-for-graalvm` modules via
make build-distro
# 2. Check generated meter classes exist
-ls
build-tools/mal-compiler/target/generated-mal-classes/org/apache/skywalking/oap/server/core/analysis/meter/dynamic/
+ls
build-tools/precompiler/target/generated-classes/org/apache/skywalking/oap/server/core/analysis/meter/dynamic/
-# 3. Check Groovy script classes exist
-ls
build-tools/mal-compiler/target/generated-mal-classes/org/apache/skywalking/oap/server/core/analysis/meter/script/
+# 3. Check transpiled Java expression classes exist
+ls
build-tools/precompiler/target/generated-classes/org/apache/skywalking/oap/server/core/source/oal/rt/mal/
# 4. Check manifest files
-cat
build-tools/mal-compiler/target/generated-mal-classes/META-INF/mal-meter-classes.txt
| wc -l
-cat
build-tools/mal-compiler/target/generated-mal-classes/META-INF/mal-groovy-scripts.txt
| wc -l
-cat
build-tools/mal-compiler/target/generated-mal-classes/META-INF/lal-scripts.txt
| wc -l
+wc -l
build-tools/precompiler/target/generated-classes/META-INF/mal-meter-classes.txt
+wc -l
build-tools/precompiler/target/generated-classes/META-INF/mal-expressions.txt
+wc -l
build-tools/precompiler/target/generated-classes/META-INF/lal-expressions.txt
-# 5. Check MeterFunction manifest (produced by oal-exporter)
-cat
build-tools/oal-exporter/target/generated-oal-classes/META-INF/annotation-scan/MeterFunction.txt
+# 5. Check MeterFunction manifest
+cat
build-tools/precompiler/target/generated-classes/META-INF/annotation-scan/MeterFunction.txt
# 6. Verify tests pass
-make build-distro # runs MALCompilerTest + MALPrecompiledRegistrationTest
+make build-distro # runs all comparison tests (1300+ assertions)
```
---
-# Phase 3: Eliminate Groovy — Pure Java MAL Transpiler
+## Pure Java MAL Transpiler
-## Why: Groovy + GraalVM Native Image is Incompatible
+### Why: Groovy + GraalVM Native Image is Incompatible
The first native-image build (`make native-image`) failed with:
@@ -490,16 +483,16 @@ that the generated Java code produces identical results
to the Groovy-compiled s
---
-## Approach: MAL-to-Java Transpiler
+### Approach: MAL-to-Java Transpiler
**Key insight**: MAL expressions are method chains on `SampleFamily` with a
well-defined
API. The precompiler already parses all 1250+ MAL rules. Instead of compiling
them to
Groovy bytecode (which needs Groovy runtime), we parse the Groovy AST at build
time and
generate equivalent Java source code. Zero Groovy at runtime.
-### What Changes
+### What the Transpiler Changes
-| Aspect | Phase 2 (Groovy pre-compilation) | Phase 3 (Java transpiler) |
+| Aspect | Before (Groovy pre-compilation) | After (Java transpiler) |
|--------|----------------------------------|--------------------------|
| Build output | Groovy `.class` bytecode | Pure Java `.class` files |
| Runtime dependency | Groovy runtime (MOP, ExpandoMetaClass) | None |
@@ -511,14 +504,14 @@ generate equivalent Java source code. Zero Groovy at
runtime.
### What Stays the Same
-- **MeterSystem Javassist generation**: Pre-compiled at build time (Phase 2),
unchanged
+- **MeterSystem Javassist generation**: Pre-compiled at build time, unchanged
- **Config data serialization**: JSON manifests for rule configs, unchanged
- **Manifest-based loading**: Same pattern, new manifest format for Java
expressions
- **MetricConvert pipeline**: Still runs at build time for Javassist class
generation
---
-## Step 1: Java Functional Interfaces for Closure Replacements
+### Java Functional Interfaces for Closure Replacements
5 `SampleFamily` methods accept `groovy.lang.Closure` parameters. Replace with
Java
functional interfaces:
@@ -559,7 +552,7 @@ Each generated filter expression class implements this
interface.
---
-## Step 2: Same-FQCN SampleFamily Replacement
+### Same-FQCN SampleFamily Replacement
**File**:
`oap-libs-for-graalvm/meter-analyzer-for-graalvm/.../dsl/SampleFamily.java`
@@ -588,7 +581,7 @@ identical — they don't use Groovy types.
---
-## Step 3: MAL-to-Java Transpiler
+### MAL-to-Java Transpiler Implementation
**File**: `build-tools/precompiler/.../MalToJavaTranspiler.java`
@@ -675,7 +668,7 @@ public class MalFilter_apisix implements MalFilter {
---
-## Step 4: Same-FQCN Expression.java Replacement
+### Same-FQCN Expression.java Replacement
**File**:
`oap-libs-for-graalvm/meter-analyzer-for-graalvm/.../dsl/Expression.java`
@@ -700,7 +693,7 @@ public class Expression {
---
-## Step 5: Update DSL.java and FilterExpression.java
+### Updated DSL.java and FilterExpression.java
### DSL.java (already exists, update)
@@ -738,7 +731,7 @@ public class FilterExpression {
---
-## Step 6: Update Precompiler
+### Precompiler Integration
Replace `compileMAL()` in `Precompiler.java` to use the transpiler instead of
Groovy
compilation:
@@ -768,9 +761,9 @@ from Phase 2). Only Groovy compilation is replaced by
transpilation.
---
-## Same-FQCN Replacements (Phase 3 — additions/updates)
+### Same-FQCN Replacements (Transpiler)
-| Upstream Class | Replacement Location | Phase 3 Change |
+| Upstream Class | Replacement Location | Change |
|---|---|---|
| `SampleFamily` | `meter-analyzer-for-graalvm/` | **New.** Closure parameters
→ functional interfaces |
| `Expression` | `meter-analyzer-for-graalvm/` | **New.** No Groovy: uses
`MalExpression` instead of `DelegatingScript` |
@@ -779,7 +772,7 @@ from Phase 2). Only Groovy compilation is replaced by
transpilation.
---
-## Files Created (Phase 3)
+### Files Created (Transpiler)
| File | Purpose |
|------|---------|
@@ -792,7 +785,7 @@ from Phase 2). Only Groovy compilation is replaced by
transpilation.
| Generated `MalExpr_*.java` files | ~1250 pure Java expression classes |
| Generated `MalFilter_*.java` files | ~29 pure Java filter classes |
-## Files Modified (Phase 3)
+### Files Modified (Transpiler)
| File | Change |
|------|--------|
@@ -803,7 +796,7 @@ from Phase 2). Only Groovy compilation is replaced by
transpilation.
---
-## Verification (Phase 3)
+### Transpiler Verification
```bash
# 1. Rebuild with transpiler
diff --git a/OAL-IMMIGRATION.md b/OAL-IMMIGRATION.md
index 7dc13bf..6366bee 100644
--- a/OAL-IMMIGRATION.md
+++ b/OAL-IMMIGRATION.md
@@ -1,4 +1,4 @@
-# Phase 2: OAL Build-Time Pre-Compilation — COMPLETE
+# OAL Build-Time Pre-Compilation
## Context
@@ -8,7 +8,7 @@ OAL engine generates metrics, builder, and dispatcher classes
at runtime via Jav
---
-## Step 1: Build-Time OAL Class Export Tool — DONE
+## Build-Time OAL Class Export Tool
**Module**: `build-tools/precompiler` (originally `build-tools/oal-exporter`,
merged into unified precompiler)
@@ -53,7 +53,7 @@ OAL engine generates metrics, builder, and dispatcher classes
at runtime via Jav
---
-## Step 2: Runtime Registration via Same-FQCN Replacement Classes — DONE
+## Runtime Registration via Same-FQCN Replacement Classes
Instead of extending upstream classes or hooking via `ModuleWiringBridge`, we
use **same-FQCN replacement**: create classes in `oap-graalvm-server` with the
exact same fully-qualified class name as the upstream class. Maven classpath
precedence ensures our version is loaded instead of the upstream version.
@@ -79,23 +79,23 @@ Same FQCN as upstream
`org.apache.skywalking.oap.server.core.source.SourceReceiv
- **No extending** — same-FQCN replacement instead of subclassing
- **No `ModuleWiringBridge` changes** — classpath precedence handles the swap
automatically
- **3 replacement classes, not 1** — `AnnotationScan` and `SourceReceiverImpl`
also needed replacement
-- **Classpath scanning fully eliminated** — not deferred to Phase 3;
annotation manifests solve it now
+- **Classpath scanning fully eliminated** — annotation manifests replace Guava
scanning
---
-## Step 3: Class Loading and Remaining Scans — DONE
+## Class Loading and Remaining Scans
### `Class.forName()` in native image
-`Class.forName()` is supported in GraalVM native image when classes are
registered in `reflect-config.json`. Since all pre-generated classes are on the
classpath at native-image build time, the GraalVM compiler includes them in the
binary. The `reflect-config.json` entries (Phase 3 task) will enable runtime
`Class.forName()` lookup. For Phase 2 (JVM mode), `Class.forName()` works
naturally.
+`Class.forName()` is supported in GraalVM native image when classes are
registered in `reflect-config.json`. Since all pre-generated classes are on the
classpath at native-image build time, the GraalVM compiler includes them in the
binary. The `reflect-config.json` entries enable runtime `Class.forName()`
lookup.
### OAL-internal scans — build-time only
The 3 OAL-internal scans (`MetricsHolder`, `DefaultMetricsFunctionRegistry`,
`FilterMatchers`) only run inside the OAL engine during `engine.start()`. They
happen at **build time** in `OALClassExporter`, not at runtime. Automatically
solved.
-### `MeterSystem` — deferred to MAL immigration
-`MeterSystem` uses Guava `ClassPath.from()` to discover meter function classes
at runtime. This is part of the MAL/meter subsystem, not OAL. Will be addressed
as part of MAL immigration (Phase 2 remaining work).
+### `MeterSystem` — solved in MAL immigration
+`MeterSystem` uses Guava `ClassPath.from()` to discover meter function classes
at runtime. Replaced with manifest-based loading. See
[MAL-IMMIGRATION.md](MAL-IMMIGRATION.md).
-### `reflect-config.json` — deferred to Phase 3
-GraalVM reflection configuration for `Class.forName()` calls on OAL-generated
and manifest-listed classes will be generated in Phase 3.
+### `reflect-config.json`
+GraalVM reflection configuration for `Class.forName()` calls on OAL-generated
and manifest-listed classes is auto-generated by the precompiler from manifests.
---
@@ -113,8 +113,8 @@ All three replacements are repackaged into
`server-core-for-graalvm` via `maven-
## Files Created
-1. **`build-tools/oal-exporter/src/main/java/.../OALClassExporter.java`**
- - Build-time tool: runs 9 OAL defines, exports `.class` files, writes OAL
manifests + annotation/interface manifests
+1. **`build-tools/precompiler/src/main/java/.../Precompiler.java`** (unified,
originally `oal-exporter`)
+ - Build-time tool: runs 9 OAL defines, exports `.class` files, writes OAL
manifests + annotation/interface manifests + reflection metadata
2.
**`oap-libs-for-graalvm/server-core-for-graalvm/src/main/java/.../core/oal/rt/OALEngineLoaderService.java`**
- Same-FQCN replacement: loads pre-compiled OAL classes from manifests
@@ -125,17 +125,9 @@ All three replacements are repackaged into
`server-core-for-graalvm` via `maven-
4.
**`oap-libs-for-graalvm/server-core-for-graalvm/src/main/java/.../core/source/SourceReceiverImpl.java`**
- Same-FQCN replacement: reads dispatcher/decorator manifests instead of
Guava classpath scanning
-5. **`build-tools/oal-exporter/src/test/java/.../OALClassExporterTest.java`**
- - 3 tests: OAL script coverage, classpath availability, full export with
manifest verification
-
-6. **`oap-graalvm-server/src/test/java/.../PrecompiledRegistrationTest.java`**
+5. **`oap-graalvm-server/src/test/java/.../PrecompiledRegistrationTest.java`**
- 12 tests: manifest vs Guava scan comparison, OAL class loading, scope
registration, source→dispatcher→metrics chain consistency
-## Files Modified
-
-1. **`build-tools/oal-exporter/pom.xml`** — dependencies + `exec-maven-plugin`
+ `maven-jar-plugin`
-2. **`oap-graalvm-server/pom.xml`** — dependency on `oal-exporter` generated
JAR
-
## Key Upstream Files (read-only)
- `OALEngineV2.java` — `start()` (parse → enrich → generate),
`notifyAllListeners()` (register)
@@ -155,16 +147,16 @@ All three replacements are repackaged into
`server-core-for-graalvm` via `maven-
make build-distro
# 2. Check generated classes exist
-ls
build-tools/oal-exporter/target/generated-oal-classes/org/apache/skywalking/oap/server/core/source/oal/rt/metrics/
-ls
build-tools/oal-exporter/target/generated-oal-classes/org/apache/skywalking/oap/server/core/source/oal/rt/dispatcher/
+ls
build-tools/precompiler/target/generated-classes/org/apache/skywalking/oap/server/core/source/oal/rt/metrics/
+ls
build-tools/precompiler/target/generated-classes/org/apache/skywalking/oap/server/core/source/oal/rt/dispatcher/
# 3. Check manifest files
-cat
build-tools/oal-exporter/target/generated-oal-classes/META-INF/oal-metrics-classes.txt
-cat
build-tools/oal-exporter/target/generated-oal-classes/META-INF/oal-dispatcher-classes.txt
+cat
build-tools/precompiler/target/generated-classes/META-INF/oal-metrics-classes.txt
+cat
build-tools/precompiler/target/generated-classes/META-INF/oal-dispatcher-classes.txt
# 4. Check annotation scan manifests
-ls
build-tools/oal-exporter/target/generated-oal-classes/META-INF/annotation-scan/
+ls build-tools/precompiler/target/generated-classes/META-INF/annotation-scan/
# 5. Verify tests pass
-make build-distro # runs both OALClassExporterTest and
PrecompiledRegistrationTest
+make build-distro # runs PrecompiledRegistrationTest
```
diff --git a/README.md b/README.md
index 993eea6..da1ad19 100644
--- a/README.md
+++ b/README.md
@@ -34,8 +34,23 @@ Requires GraalVM JDK 25.
# Initialize submodule
git submodule update --init --recursive
-# Full build (precompiler + tests + server)
+# Build upstream SkyWalking (first time only)
+JAVA_HOME=/path/to/graalvm-jdk-25 make build-skywalking
+
+# Compile distro (precompiler + tests + server)
JAVA_HOME=/path/to/graalvm-jdk-25 make build-distro
+
+# Build native image (requires GraalVM with native-image)
+JAVA_HOME=/path/to/graalvm-jdk-25 make native-image
+
+# Build native image for Docker on macOS (cross-compiles via Docker)
+make native-image-macos
+
+# Package into Docker image
+make docker-native
+
+# Run with docker-compose (BanyanDB + OAP native)
+docker compose -f docker/docker-compose.yml up
```
## Project Structure
@@ -44,16 +59,22 @@ JAVA_HOME=/path/to/graalvm-jdk-25 make build-distro
skywalking-graalvm-distro/
├── skywalking/ # Git submodule — DO NOT MODIFY
├── build-tools/
-│ ├── precompiler/ # Build-time OAL + MAL + LAL pre-compilation
-│ └── config-generator/ # (planned) Build-time config code
generation
-├── oap-graalvm-server/
+│ ├── precompiler/ # Build-time OAL + MAL + LAL
pre-compilation + reflection metadata
+│ └── config-generator/ # Build-time config code generation
(YamlConfigLoaderUtils)
+├── oap-libs-for-graalvm/ # Per-JAR repackaged modules (same-FQCN
replacements via shade)
+├── oap-graalvm-server/ # GraalVM-ready OAP server (JVM distro)
│ └── src/
│ ├── main/java/ # Same-FQCN replacement classes
-│ └── test/java/ # 1,300 comparison tests
+│ └── test/java/ # 1,300+ comparison tests
+├── oap-graalvm-native/ # Native image module (native-maven-plugin
+ assembly)
+├── docker/
+│ ├── Dockerfile.native # Runtime image (debian:bookworm-slim +
native binary)
+│ └── docker-compose.yml # BanyanDB + OAP native for local testing
├── DISTRO-POLICY.md # Build plan with phase tracking
├── OAL-IMMIGRATION.md # OAL pre-compilation design
├── MAL-IMMIGRATION.md # MAL pre-compilation design
-└── LAL-IMMIGRATION.md # LAL pre-compilation design
+├── LAL-IMMIGRATION.md # LAL pre-compilation design
+└── CONFIG-INIT-IMMIGRATION.md # Config initialization design
```
## Documentation
@@ -62,8 +83,9 @@ skywalking-graalvm-distro/
|---|---|
| [DISTRO-POLICY.md](DISTRO-POLICY.md) | Build plan, module selection, phase
tracking, risk assessment |
| [OAL-IMMIGRATION.md](OAL-IMMIGRATION.md) | OAL (Observability Analysis
Language) pre-compilation: Javassist class export, annotation scanning, runtime
manifests |
-| [MAL-IMMIGRATION.md](MAL-IMMIGRATION.md) | MAL (Meter Analysis Language)
pre-compilation: Groovy script compilation, Javassist meter classes,
combination pattern |
-| [LAL-IMMIGRATION.md](LAL-IMMIGRATION.md) | LAL (Log Analysis Language)
pre-compilation: static Groovy compilation, SHA-256 manifest lookup |
+| [MAL-IMMIGRATION.md](MAL-IMMIGRATION.md) | MAL (Meter Analysis Language)
pre-compilation: Groovy-to-Java transpilation, Javassist meter classes,
combination pattern |
+| [LAL-IMMIGRATION.md](LAL-IMMIGRATION.md) | LAL (Log Analysis Language)
pre-compilation: Groovy-to-Java transpilation, SHA-256 manifest lookup |
+| [CONFIG-INIT-IMMIGRATION.md](CONFIG-INIT-IMMIGRATION.md) | Config
initialization: reflection-free config loading via generated code |
## License
Apache 2.0