Skip to content

Enable Gradle enhanced graph ordering - #12326

Draft
AlexeyKuznetsov-DD wants to merge 1 commit into
alexeyk/upgrade-gradle-9.7.1from
alexeyk/gradle-enhanced-graph-ordering
Draft

Enable Gradle enhanced graph ordering#12326
AlexeyKuznetsov-DD wants to merge 1 commit into
alexeyk/upgrade-gradle-9.7.1from
alexeyk/gradle-enhanced-graph-ordering

Conversation

@AlexeyKuznetsov-DD

@AlexeyKuznetsov-DD AlexeyKuznetsov-DD commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

What Does This Do

  • Enables Gradle 9.7's ENHANCED_GRAPH_ORDERING feature preview.
  • Keeps the SofaRPC Netty alignment constraint because enhanced ordering changes which duplicate class wins but cannot reconcile classes embedded in an unrelated fat JAR.
  • Replaces MockServer's JUnit integration artifact with mockserver-netty-no-dependencies:5.14.0 and a minimal local JUnit extension, avoiding embedded JUnit and incompatible SLF4J classes.
  • Excludes the tracer's unrelocated OkHttp and Okio forks from OpenAI test runtime classpaths, where they can shadow OpenAI's newer upstream versions.
  • Centralizes Spring Boot Shadow JAR configuration in a build-logic/spring-boot-shadow convention that merges service and Spring discovery metadata.
  • Preserves historical first-file Spring factories behavior in two legacy smoke fixtures that depend on it, while applying the shared convention to the remaining Spring Boot smoke applications.
  • Pins the Quartz 2.4 compatibility suite to Quartz 2.4.0 and its matching javax.transaction API, and refreshes ordering-sensitive dependency locks.
  • Extracts namespace-neutral Liberty classloader naming and multipart hooks into a shared module, while restricting servlet-specific advice to the matching javax or jakarta generation.

Motivation

Gradle 9.6 changed dependency traversal and could place an older fat JAR before newer modular dependencies. Gradle 9.7 addresses that traversal behavior behind ENHANCED_GRAPH_ORDERING; the preview becomes the default in Gradle 10.

Enabling the preview also reveals classpaths that previously depended on incidental traversal order. Some are normal dependency conflicts that can be made deterministic through exclusions or direct dependencies. Others involve classes or resources hidden inside fat/no-dependencies JARs, which Gradle cannot reconcile by module version because they belong to different coordinates.

SofaRPC is in the latter category: sofa-rpc-all:5.14.2 brings the class-carrying netty-all:4.1.44.Final, while gRPC brings individual Netty 4.1.79 modules. Enhanced ordering changes which copy of io.netty.** loads first, but does not eliminate the duplicate classes. Retaining the constraint on netty-all:4.1.79.Final replaces the fat JAR with Netty's class-free aggregator and an aligned modular dependency set.

The ordering change also exposed two structural issues. Spring Boot fat JARs normally need discovery metadata from every dependency merged rather than retaining an arbitrary duplicate, and Liberty 20 and Liberty 23 reuse IBM implementation class names even though their servlet APIs use different namespaces. The Spring convention makes metadata handling consistent for normal fixtures, while the Liberty common module removes an unnecessary cross-generation test dependency and namespace matchers prevent incompatible servlet advice from being applied.

Additional Notes

This is stacked on #12323 and should be reviewed and merged after it.

The SofaRPC regression can otherwise combine AbstractReferenceCountedByteBuf from Netty 4.1.79 with ReferenceCountUpdater from the 4.1.44 fat JAR and fail with a NoSuchMethodError. With enhanced ordering, the old fat JAR may instead win for all Netty classes, hiding that particular linkage error while silently testing the wrong Netty version. The retained constraint removes both outcomes.

MockServer's previous mockserver-junit-jupiter-no-dependencies artifact embeds an older JUnit Platform under the original packages. Enhanced ordering allowed those classes to shadow JUnit Platform 1.14.1, producing:

java.lang.NoSuchMethodError:
  org.junit.platform.commons.util.CollectionUtils.forEachInReverseOrder(...)

The replacement uses mockserver-netty-no-dependencies, which contains the server implementation without embedded JUnit classes, plus a small extension implementing only the lifecycle and parameter injection used by the HTTP test fixtures. Version 5.14.0 is intentional: its unrelocated SLF4J API matches this module's SLF4J 1.7 line and it ships no logging provider, whereas 5.15.0 embeds SLF4J 2.0 and a JUL provider.

The OpenAI test classpath contains both Datadog's forked OkHttp/Okio and OpenAI's newer upstream versions under identical Java packages. Runtime-only exclusions preserve the tested OpenAI versions and avoid failures such as:

java.lang.NoSuchFieldError:
  okhttp3.MediaType$Companion Companion

The Spring Boot Shadow convention merges META-INF/services, Spring handlers, schemas, tooling, and factories. It lives in a separate Java 17 build-logic module because Shadow 9's plugin API targets Java 17, while other build-logic modules still target Java 8. appsec/springboot and the legacy Spring Boot 1.5 IAST fixture intentionally keep raw Shadow behavior plus a direct spring-boot-autoconfigure dependency. Merging their complete factory sets changes established request/error behavior: the AppSec fixture stops observing expected blocking, and the Java 8/11 IAST fixture reports RIPEMD128 MessageDigest not available. The direct dependency makes their historical first-file selection deterministic under enhanced ordering.

The Quartz version40Test suite is pinned to Quartz 2.4.0 so it remains distinct from latestDepTest. Quartz 2.4 uses javax.transaction.UserTransaction; Quartz 2.5 and later use Jakarta Transactions.

Liberty 23 previously loaded the complete Liberty 20 instrumentation module in tests to reuse deployment classloader naming. The shared module now contains the namespace-neutral classloader naming and multipart filename hooks. Request and response finish instrumentations retain symmetric javax.servlet and jakarta.servlet structure matchers because the production agent packages both generations. As a diagnostic, both module suites also passed with those matchers temporarily disabled after the test dependency was decoupled, but that isolated test setup does not model both generations being loaded by the production agent.

Validation:

  • ./gradlew :components:http:http-api:check :components:http:http-api:forkedTest :dd-java-agent:instrumentation:openai-java:openai-java-3.0:test :dd-java-agent:instrumentation:openai-java:openai-java-3.0:forkedTest :dd-java-agent:instrumentation:openai-java:openai-java-3.0:latestDepTest :dd-java-agent:instrumentation:sofarpc:sofarpc-5.0:test :dd-java-agent:instrumentation:sofarpc:sofarpc-5.0:forkedTest :dd-java-agent:instrumentation:sofarpc:sofarpc-5.0:latestDepTest :dd-smoke-tests:spring-boot-2.5-webflux:test -PtestJvm=17 --rerun-tasks (197 tests passed, 0 failed; 3 intentionally disabled HTTP-provider tests skipped)
  • ./gradlew :components:http:http-api:compileTestFixturesJava :components:http:http-api:forkedTest -PtestJvm=11 --rerun-tasks
  • ./gradlew :components:http:http-api:compileTestFixturesJava :components:http:http-api:forkedTest -PtestJvm=25 --rerun-tasks
  • ./gradlew :dd-java-agent:instrumentation:quartz-2.0:test :dd-java-agent:instrumentation:quartz-2.0:version40Test :dd-java-agent:instrumentation:quartz-2.0:latestDepTest --rerun-tasks (4 tests passed in each suite)
  • ./gradlew :dd-java-agent:instrumentation:spring:spring-webflux:spring-webflux-5.0:iastTest --rerun-tasks (8 tests passed)
  • ./gradlew :dd-smoke-tests:spring-boot-2.4-webflux:test :dd-smoke-tests:springboot-mongo:test -PtestJvm=17 --rerun-tasks (3 tests passed in each suite)
  • ./gradlew :dd-smoke-tests:appsec:springboot:test -PtestJvm=17 --rerun-tasks
  • ./gradlew :dd-smoke-tests:springboot:test -PtestJvm=8 --rerun-tasks (211 tests passed, 0 failed)
  • The AppSec blocking regression test passed individually on Java 8, 17, and 25; the legacy IAST regression test passed individually on Java 8 and 11.
  • ./gradlew :dd-java-agent:instrumentation:liberty:liberty-20.0:test :dd-java-agent:instrumentation:liberty:liberty-20.0:forkedTest :dd-java-agent:instrumentation:liberty:liberty-23.0:test :dd-java-agent:instrumentation:liberty:liberty-23.0:forkedTest -PtestJvm=17 --rerun-tasks (527 tests passed, 0 failed)
  • ./gradlew :dd-java-agent:instrumentation:liberty:liberty-20.0:muzzle :dd-java-agent:instrumentation:liberty:liberty-23.0:muzzle (2 checks passed)
  • ./gradlew :dd-java-agent:instrumentation:liberty:liberty-common:build
  • ./gradlew -p build-logic :spring-boot-shadow:check
  • ./gradlew :dd-java-agent:shadowJar

Gradle issue: gradle/gradle#38057

Contributor Checklist

Jira ticket: [PROJ-IDENT]

@AlexeyKuznetsov-DD AlexeyKuznetsov-DD added tag: no release notes Changes to exclude from release notes type: refactoring comp: tooling Build & Tooling tag: ai generated Largely based on code generated by an AI or LLM labels Aug 27, 2026
@AlexeyKuznetsov-DD AlexeyKuznetsov-DD self-assigned this Aug 27, 2026
@AlexeyKuznetsov-DD
AlexeyKuznetsov-DD marked this pull request as ready for review August 27, 2026 20:42
@AlexeyKuznetsov-DD
AlexeyKuznetsov-DD requested review from a team as code owners August 27, 2026 20:42
@AlexeyKuznetsov-DD
AlexeyKuznetsov-DD requested review from ValentinZakharov and removed request for a team August 27, 2026 20:42

@datadog-datadog-prod-us1-2 datadog-datadog-prod-us1-2 Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Datadog Autotest: PASS

More details

The changes use established repository patterns for dependency exclusions, MockServer setup, and Spring metadata merge. The static review finds no concrete failure.

Was this helpful? React 👍 or 👎

Open Bits AI session

🤖 Datadog Autotest · Commit c6e34cd · What is Autotest? · @DataDog review to ask questions · Any feedback? Reach out in #autotest

@datadog-datadog-prod-us1-2

This comment has been minimized.

@dd-octo-sts

dd-octo-sts Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

🟢 Java Benchmark SLOs — All performance SLOs passed

Suite Status
Startup 🟢 pass

SLO thresholds are defined here based on automatically generated metrics. A warning is raised when results are within 5% of the threshold.

PR vs. master results
Scenario Candidate master Δ (95% CI of mean)
startup:insecure-bank:iast:Agent 14.80 s 14.68 s [+0.1%; +1.5%] (maybe worse)
startup:insecure-bank:tracing:Agent 13.67 s 13.70 s [-1.0%; +0.6%] (no difference)
startup:petclinic:appsec:Agent 17.50 s 16.58 s [+1.2%; +10.0%] (significantly worse)
startup:petclinic:iast:Agent 17.44 s 17.61 s [-1.9%; +0.0%] (no difference)
startup:petclinic:profiling:Agent 17.48 s 17.40 s [-1.0%; +1.9%] (no difference)
startup:petclinic:sca:Agent 16.99 s 17.30 s [-6.2%; +2.6%] (no difference)
startup:petclinic:tracing:Agent 16.75 s 16.69 s [-0.6%; +1.4%] (no difference)

Commit: 88bf0eef · CI Pipeline · Benchmarking Platform UI


Load and DaCapo benchmarks can be triggered manually in the GitLab pipeline. Results will appear in the Benchmarking Platform UI after completion.

@AlexeyKuznetsov-DD
AlexeyKuznetsov-DD force-pushed the alexeyk/gradle-enhanced-graph-ordering branch from c6e34cd to bdb9131 Compare August 27, 2026 23:02
@AlexeyKuznetsov-DD
AlexeyKuznetsov-DD force-pushed the alexeyk/gradle-enhanced-graph-ordering branch from bdb9131 to 88bf0ee Compare August 28, 2026 01:25
@AlexeyKuznetsov-DD
AlexeyKuznetsov-DD marked this pull request as draft August 28, 2026 01:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp: tooling Build & Tooling tag: ai generated Largely based on code generated by an AI or LLM tag: no release notes Changes to exclude from release notes type: refactoring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant