TECH_DEBT: Updating Java and Spring Boot Versions#1510
TECH_DEBT: Updating Java and Spring Boot Versions#1510seanmcilvenna wants to merge 2 commits intodevfrom
Conversation
…ies and configurations: - Updated base images to Java 21 in Dockerfiles. - Migrated `javax.servlet` imports to `jakarta.servlet` - Enabled Spring virtual threads for validation and measureeval. - Updated Spring Boot to 3.4.3 and aligned BOM dependencies (Spring Cloud, Azure, OpenTelemetry). - Upgraded HAPI-FHIR to version 7.6.1 with associated dependency updates. - Improved OpenTelemetry configuration following API changes. - Integrated CDS and optimized runtime entrypoints.
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThis PR upgrades the Java ecosystem across multiple modules: Spring Boot from 3.2.5 to 3.4.3, Java runtime from 17 to 21, and migrates servlet APIs from javax to jakarta. Docker configurations are refactored to use Spring Boot's jarmode extraction and JarLauncher with Class Data Sharing. OpenTelemetry and Spring Cloud dependencies are updated. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
jakarta.servlet, and align dependencies and configurations: - Updated base images to Java 21 in Dockerfiles. - Migrated javax.servlet imports to jakarta.servlet - Enabled Spring virtual threads for validation and measureeval. - Updated Spring Boot to 3.4.3 and aligned BOM dependencies (Spring Cloud, Azure, OpenTelemetry). - Upgraded HAPI-FHIR to version 7.6.1 with associated dependency updates. - Improved OpenTelemetry configuration following API changes. - Integrated CDS and optimized runtime entrypoints.There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@Java/measureeval/Dockerfile`:
- Around line 21-22: The Dockerfile currently runs the jarmode extraction (java
-Djarmode=tools -jar measureeval.jar extract --launcher ...) which only creates
the app layout but does not produce the CDS archive; add a training run
immediately after the extract to generate application.jsa by invoking the JVM
with -XX:ArchiveClassesAtExit=application.jsa and launching the Spring Boot
launcher (org.springframework.boot.loader.launch.JarLauncher) so the CDS archive
is created before the ENTRYPOINT attempts to load application.jsa.
In `@Java/pom.xml`:
- Around line 101-120: The RuntimeMetrics behavior changed in the updated
OpenTelemetry/instrumentation BOMs:
RuntimeMetrics.builder().enableAllFeatures().build() in your OpenTelemetryConfig
files now emits JVM runtime metrics in seconds (v2.8.0+); confirm downstream
consumers expect seconds and, if they expect milliseconds, either change the
consumers to interpret the unit as seconds or modify the metrics pipeline in
your OpenTelemetryConfig to convert values back to milliseconds and set the
metric unit to "ms" (or explicitly set the unit via the runtime metric
configuration API if available) so
RuntimeMetrics.builder().enableAllFeatures().build() produces values and unit
compatible with downstream systems.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 6a1fc5b5-fb61-470a-a862-f9df4f76df1b
📒 Files selected for processing (14)
Java/hapi/DockerfileJava/hapi/pom.xmlJava/hapi/src/main/java/ca/uhn/fhir/jpa/starter/link/filters/RequestConcurrencyLoggingFilter.javaJava/hapi/src/main/java/ca/uhn/fhir/jpa/starter/link/filters/RequestRateLimitingFilter.javaJava/hapi/src/main/java/com/lantanagroup/link/hapi/utils/HttpServletRequestUtils.javaJava/measureeval/DockerfileJava/measureeval/pom.xmlJava/measureeval/src/main/java/com/lantanagroup/link/measureeval/configs/OpenTelemetryConfig.javaJava/measureeval/src/main/resources/application.ymlJava/pom.xmlJava/validation/DockerfileJava/validation/pom.xmlJava/validation/src/main/java/com/lantanagroup/link/validation/configs/OpenTelemetryConfig.javaJava/validation/src/main/resources/application.yml
| # Extract using tools jarmode (replacement for layertools and cds in SB 3.4) | ||
| RUN java -Djarmode=tools -jar measureeval.jar extract --launcher --destination . --force |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Spring Boot 3.4 jarmode tools extract CDS archive generation
💡 Result:
To generate a CDS (AppCDS) archive for a Spring Boot 3.4 executable JAR, you use the tools jarmode to extract the JAR into a CDS-friendly layout, then do a “training run” that writes the archive on exit, and finally launch using that archive.
1) Extract the executable JAR (CDS-friendly layout)
java -Djarmode=tools -jar my-app.jar extract --destination applicationThis tools jarmode extract command is the modern replacement for -Djarmode=layertools extract. [1]
2) Training run: generate the CDS archive (application.jsa)
Run from the extracted directory (so the classpath/layout is stable for CDS):
cd application
java -XX:ArchiveClassesAtExit=application.jsa \
-Dspring.context.exit=onRefresh \
-jar my-app.jarThis produces application.jsa. [2][3]
3) Production run: use the archive
java -XX:SharedArchiveFile=application.jsa -jar my-app.jar(Again, run using the same extracted layout.) [2][3]
Buildpacks (optional, container images)
If you build an image with Paketo buildpacks via Spring Boot, you can enable automatic CDS training + packaging by setting:
BP_JVM_CDS_ENABLED=true[4][5]
And if the training run needs different JVM/app options (e.g., to prevent early DB connections), you can use:
CDS_TRAINING_JAVA_TOOL_OPTIONS[5]
Sources: Spring Boot 3.3+ tools jarmode (still applies to 3.4) [1], Spring Boot CDS reference/how-to docs [2][4], Spring blog (CDS + self-extracting JAR workflow) [5].
Add missing CDS archive training run.
The extract --launcher command only creates the application structure; it does not generate the application.jsa CDS archive. A separate training run is required between extraction and production:
Required Docker step
RUN java -Djarmode=tools -jar measureeval.jar extract --launcher --destination . --force && \
java -XX:ArchiveClassesAtExit=application.jsa \
-Dspring.context.exit=onRefresh \
org.springframework.boot.loader.launch.JarLauncherWithout this step, the ENTRYPOINT will fail when attempting to load the non-existent application.jsa archive.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Java/measureeval/Dockerfile` around lines 21 - 22, The Dockerfile currently
runs the jarmode extraction (java -Djarmode=tools -jar measureeval.jar extract
--launcher ...) which only creates the app layout but does not produce the CDS
archive; add a training run immediately after the extract to generate
application.jsa by invoking the JVM with
-XX:ArchiveClassesAtExit=application.jsa and launching the Spring Boot launcher
(org.springframework.boot.loader.launch.JarLauncher) so the CDS archive is
created before the ENTRYPOINT attempts to load application.jsa.
| <dependency> | ||
| <groupId>io.opentelemetry</groupId> | ||
| <artifactId>opentelemetry-bom</artifactId> | ||
| <version>1.38.0</version> | ||
| <version>1.47.0</version> | ||
| <type>pom</type> | ||
| <scope>import</scope> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>io.opentelemetry.instrumentation</groupId> | ||
| <artifactId>opentelemetry-instrumentation-bom-alpha</artifactId> | ||
| <version>2.4.0-alpha</version> | ||
| <version>2.13.0-alpha</version> | ||
| <type>pom</type> | ||
| <scope>import</scope> | ||
| </dependency> | ||
|
|
||
| <dependency> | ||
| <groupId>io.opentelemetry.instrumentation</groupId> | ||
| <artifactId>opentelemetry-runtime-telemetry-java17</artifactId> | ||
| <version>2.4.0-alpha</version> | ||
| <version>2.13.0-alpha</version> | ||
| </dependency> |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify OpenTelemetry API changes that might affect code in the repository
# Search for OpenTelemetry usage patterns that may have changed between versions
echo "=== Searching for ResourceAttributes usage (deprecated in newer versions) ==="
rg -n "ResourceAttributes" --type java
echo "=== Searching for OpenTelemetry SDK configuration patterns ==="
rg -n "SdkTracerProvider|SdkMeterProvider|AutoConfiguredOpenTelemetrySdk" --type javaRepository: lantanagroup/link-cloud
Length of output: 1503
🏁 Script executed:
cat -n Java/validation/src/main/java/com/lantanagroup/link/validation/configs/OpenTelemetryConfig.javaRepository: lantanagroup/link-cloud
Length of output: 4410
🏁 Script executed:
cat -n Java/measureeval/src/main/java/com/lantanagroup/link/measureeval/configs/OpenTelemetryConfig.javaRepository: lantanagroup/link-cloud
Length of output: 4028
🏁 Script executed:
# Check if there are any other OpenTelemetry related files
fd -e java -t f | xargs grep -l "opentelemetry" | head -20Repository: lantanagroup/link-cloud
Length of output: 1550
🏁 Script executed:
grep -n "opentelemetry" Java/measureeval/src/main/java/com/lantanagroup/link/measureeval/services/MeasureEvalMetrics.javaRepository: lantanagroup/link-cloud
Length of output: 309
🏁 Script executed:
grep -n "opentelemetry" Java/validation/src/main/java/com/lantanagroup/link/validation/services/MetricService.javaRepository: lantanagroup/link-cloud
Length of output: 219
🏁 Script executed:
grep -n "opentelemetry" Java/measureeval/src/main/java/com/lantanagroup/link/measureeval/filters/TracingFilter.javaRepository: lantanagroup/link-cloud
Length of output: 108
🌐 Web query:
OpenTelemetry Java 1.38.0 to 1.47.0 breaking changes migration guide
💡 Result:
OpenTelemetry Java (opentelemetry-java) migration: 1.38.0 → 1.47.0 (breaking changes you must handle)
Use the BOM and upgrade all io.opentelemetry:* artifacts in lockstep to avoid runtime linkage issues (recommended for this repo).
1) 1.39.0 (2024-06-07) — Incubator + Prometheus exporter breaking changes
- Incubator:
ExtendedTracer/ExtendedSpanBuilderrefactor (expect compilation fixes if you use the incubator APIs; update imports/usages to the new shapes). [1] - Prometheus exporter: Prometheus metrics are served only on
/metricsby default (update your scrape config / reverse-proxy routing accordingly). [1]
2) 1.42.0 (2024-09-06) — Logs AnyValue body stabilization (type + package rename)
- Breaking: Log body “AnyValue” stabilization:
AnyValuerenamed toValue- moved from
opentelemetry-api-incubatortoopentelemetry-api - package changed from
io.opentelemetry.api.incubator.logstoio.opentelemetry.api.common[2]
Migration: update dependencies (stop relying on incubator for this) and fix imports/types toio.opentelemetry.api.common.Value.
3) 1.46.0 (2025-01-10) — Autoconfigure: deprecated property removed
- Breaking: autoconfigure dropped support for deprecated
otel.experimental.resource.disabled.keys.
Migration: useotel.resource.disabled.keysinstead. [3]
4) 1.47.0 (2025-02-07) — Event API/SDK removed
- Breaking: Event API / SDK dropped. [4]
Migration: replace Event API usage with the Logs API (and/or incubator helpers added around log “event name”, e.g.ExtendedLogRecordBuilder#setEventName, depending on what you were doing). [4]
Quick “what to do” checklist
- Update your BOM:
io.opentelemetry:opentelemetry-bom:1.47.0(and keep all OTel module versions aligned). - If you use Prometheus exporter: ensure your Prometheus job scrapes
/metrics. [1] - If you emit structured log bodies: migrate
AnyValue→Valueand fix imports/packages. [2] - If you relied on Event API: migrate to Logs (Event API is gone in 1.47.0). [4]
- If you use autoconfigure resource-key disabling: replace
otel.experimental.resource.disabled.keyswithotel.resource.disabled.keys. [3]
Sources: OpenTelemetry Java CHANGELOG.md for 1.39.0, 1.42.0, 1.46.0, 1.47.0. [1][2][3][4]
🌐 Web query:
OpenTelemetry Instrumentation 2.4.0-alpha to 2.13.0-alpha breaking changes
💡 Result:
Breaking / migration-impacting changes called out in upstream opentelemetry-java-instrumentation release notes between v2.4.0 and v2.13.0 (these affect the 2.x.y-alpha artifacts shipped with each release):
-
v2.13.0 (2025-02-17)
io.opentelemetry.instrumentation.api.incubator.semconv.util.SpanNamesdeprecated → use stableio.opentelemetry.instrumentation.api.semconv.util.SpanNames.- Previously-deprecated HTTP library instrumentation classes/methods removed (from prior two releases).
- Deprecated Dubbo instrumentation method removed. [1]
-
v2.12.0 (2025-01-17)
- Some Java agent instrumentation suppression keys renamed to match module names (e.g.,
elasticsearch-rest-6.0→elasticsearch-rest-6.4,internal-application-logging→internal-application-logger, etc.). *TelemetryBuilderAPI parameter types changed:setCaptured*Headers(List)→setCaptured*Headers(Collection);setKnownMethods(Set)→setKnownMethods(Collection). [2]
- Some Java agent instrumentation suppression keys renamed to match module names (e.g.,
-
v2.11.0 (2024-12-23) (prep for HTTP instrumentation stabilization)
addAttributeExtractordeprecated/renamed →addAttributesExtractor.setEmitExperimental*deprecated and moved to internal/experimental classes.ApacheHttpClient5*deprecated/renamed →ApacheHttpClient*.RatpackTelemetry*,SpringWebfluxTelemetry*,ArmeriaTelemetry*deprecated/split into*ClientTelemetry*and*ServerTelemetry*.*Ktor*Tracing*deprecated/renamed →*Ktor*Telemetry*.- Experimental attribute
spring-webflux.handler.typeremoved (usecode.*attributes). [3]
-
v2.10.0 (2024-11-13)
- Spring Boot Starter scheduling instrumentation scope name changed:
io.opentelemetry.spring-scheduling-3.1→io.opentelemetry.spring-boot-autoconfigure. - AWS Lambda javaagent default flush timeout changed 1s → 10s. [4]
- Spring Boot Starter scheduling instrumentation scope name changed:
-
v2.9.0 (2024-10-17)
- Opt-in attribute renamed
aws.requestId→aws.request_id, and it is now emitted by default. [5]
- Opt-in attribute renamed
-
v2.8.0 (2024-09-13)
- Java 17 JFR-based runtime metrics unit changed milliseconds → seconds (only if opted-in via
otel.instrumentation.runtime-telemetry-java17.enable-all=true). [6]
- Java 17 JFR-based runtime metrics unit changed milliseconds → seconds (only if opted-in via
-
v2.6.0 (2024-07-17)
- Spring Boot autoconfigure artifacts merged:
opentelemetry-spring-boot+opentelemetry-spring-boot-3→opentelemetry-spring-boot-autoconfigure(supports both Boot 2 & 3). - Experimental HTTP metrics renamed:
http.server.request.size→http.server.request.body.size;http.server.response.size→http.server.response.body.size. [7]
- Spring Boot autoconfigure artifacts merged:
-
v2.4.0 (2024-05-17)
- Removed incubating semconv dependency from library instrumentation (can affect dependency graphs). [8]
Sources: GitHub release notes for v2.13.0 [1], v2.12.0 [2], v2.11.0 [3], v2.10.0 [4], v2.9.0 [5], v2.8.0 [6], v2.6.0 [7], v2.4.0 [8].
Verify RuntimeMetrics metric unit compatibility with downstream systems.
The OpenTelemetry BOM update (1.38.0 → 1.47.0) and instrumentation update (2.4.0-alpha → 2.13.0-alpha) introduce significant changes. Most breaking changes in these ranges do not affect the code here (e.g., Event API removal, AnyValue renaming, Prometheus exporter config). However, v2.8.0 introduced a breaking change directly affecting this codebase: Java 17 runtime metrics now emit in seconds instead of milliseconds when using RuntimeMetrics.builder().enableAllFeatures().build() (lines 71 in both OpenTelemetryConfig files).
Confirm that downstream systems consuming these metrics expect second-based units, or update the metric unit configuration accordingly.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Java/pom.xml` around lines 101 - 120, The RuntimeMetrics behavior changed in
the updated OpenTelemetry/instrumentation BOMs:
RuntimeMetrics.builder().enableAllFeatures().build() in your OpenTelemetryConfig
files now emits JVM runtime metrics in seconds (v2.8.0+); confirm downstream
consumers expect seconds and, if they expect milliseconds, either change the
consumers to interpret the unit as seconds or modify the metrics pipeline in
your OpenTelemetryConfig to convert values back to milliseconds and set the
metric unit to "ms" (or explicitly set the unit via the runtime metric
configuration API if available) so
RuntimeMetrics.builder().enableAllFeatures().build() produces values and unit
compatible with downstream systems.
smailliwcs
left a comment
There was a problem hiding this comment.
The hapi module needs to be compatible with the version of HAPI running on ehr-test. (See notes in the POM and Dockerfile.) So until we're ready to upgrade ehr-test, we need to keep the module on Java 11 and HAPI 5.6.0.
🛠️ Description of Changes
Upgrade to Java 21, migrate to
jakarta.servlet, and align dependencies and configurations:javax.servletimports tojakarta.servlet🧪 Testing Performed
Ran with docker compose, successfully tested against a basic synthetic test patient.
🧑🔬 Unit Testing
Unit tests not applicable for this change.
📓 Documentation Updated
N/A
Summary by CodeRabbit
Release Notes
New Features
Upgrades
Performance