Skip to content

Make snakeyaml-engine and jackson-databind optional at runtime#8270

Open
zeitlinger wants to merge 10 commits intoopen-telemetry:mainfrom
zeitlinger:optional-yaml-dep
Open

Make snakeyaml-engine and jackson-databind optional at runtime#8270
zeitlinger wants to merge 10 commits intoopen-telemetry:mainfrom
zeitlinger:optional-yaml-dep

Conversation

@zeitlinger
Copy link
Copy Markdown
Member

@zeitlinger zeitlinger commented Apr 9, 2026

Summary

This PR does two things:

1. Split YAML parsing out of DeclarativeConfiguration

DeclarativeConfiguration is split into two classes to make YAML dependencies optional at runtime:

  • DeclarativeConfigurationcreate(model) methods only. No dependency on snakeyaml-engine or jackson-databind at runtime.
  • DeclarativeConfigurationParser — all YAML parsing: MAPPER static block, parse(), loadYaml(), parseAndCreate(), toConfigProperties(), env-var substitution.

The MAPPER field in the original class is a static final with a static initializer. Loading the class to call create(model) triggered that static block, failing with NoClassDefFoundError if jackson-databind was absent. Moving the static block to DeclarativeConfigurationParser breaks the link — the JVM only loads it when parser methods are actually called.

2. Move all declarative config (fileconfig) from incubator into autoconfigure

All ~45 fileconfig source files are moved from sdk-extensions/incubator to sdk-extensions/autoconfigure. This is the direction suggested in #8265 — the YAML dep concern is resolved by the class split above.

A new sdk-extensions/autoconfigure-config convenience module bundles autoconfigure + snakeyaml-engine + jackson-databind for users who want everything in one dependency (Spring Boot starter style).

Dependency graph

graph TD
    config["autoconfigure-config\n(convenience bundle)"]
    autoconfigure["autoconfigure\n(fileconfig included)"]
    incubator["incubator\n(ViewConfig, SPI extensions)"]
    api-incubator["api:incubator"]
    snakeyaml["snakeyaml-engine"]
    jackson["jackson-databind"]
    jackson-ann["jackson-annotations"]

    config -->|api| autoconfigure
    config -->|runtimeOnly| snakeyaml
    config -->|runtimeOnly| jackson

    autoconfigure -->|api| jackson-ann
    autoconfigure -.->|"compileOnly (YAML parsing)"| snakeyaml
    autoconfigure -.->|"compileOnly (YAML parsing)"| jackson
    autoconfigure -.->|"compileOnly (fileconfig)"| api-incubator
    autoconfigure -.->|"compileOnly (optional SPI)"| incubator

    incubator -->|api| api-incubator
Loading

Dashed arrows = compileOnly / optional at runtime. YAML file config requires snakeyaml + jackson + api:incubator at runtime; autoconfigure-config provides all three.

What changes for users

Use case Before After
AutoConfiguredOpenTelemetrySdk (env/props only) autoconfigure autoconfigure (unchanged)
YAML file config (otel.config.file) autoconfigure + incubator + snakeyaml + jackson autoconfigure-config
Programmatic DeclarativeConfiguration.create(model) incubator + snakeyaml + jackson (YAML deps leaked) autoconfigure only
SPI-based declarative config autoconfigure + incubator + api:incubator same

Related to / supersedes the direction in #8265.

Split DeclarativeConfiguration into two classes:
- DeclarativeConfiguration: create(model) only, no YAML/jackson-databind deps
- DeclarativeConfigurationParser: all parsing (MAPPER static block, parse,
  loadYaml, parseAndCreate, toConfigProperties, createSampler, env-var
  substitution, snakeyaml inner classes)

Change snakeyaml-engine and jackson-databind from implementation to
compileOnly in build.gradle.kts (keeping jackson-annotations as api since
the generated model POJOs use @JsonProperty etc. as public API).
Remove the unused jackson-dataformat-yaml dependency.

Users who only call DeclarativeConfiguration.create(model) for programmatic
SDK configuration no longer incur transitive YAML/jackson-databind deps.
Users who need YAML parsing add snakeyaml-engine and jackson-databind and
call DeclarativeConfigurationParser.parseAndCreate(stream).

This also opens the door for merging declarative config into autoconfigure,
since the static initializer that caused NoClassDefFoundError when
jackson-databind was absent is now isolated in DeclarativeConfigurationParser.
Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
…rser

Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
…module

- All fileconfig source files moved from sdk-extensions/incubator to sdk-extensions/autoconfigure, removing the hard dependency on incubator for users who only need autoconfigure
- New testDeclarativeConfig test suite in autoconfigure with isolated classpath so existing autoconfigure tests (which check for absent exporters) are not polluted
- Updated INCUBATOR_AVAILABLE check to look for api:incubator (DeclarativeConfigException), and added separate PARSER_AVAILABLE check for snakeyaml
- New sdk-extensions/autoconfigure-config convenience module that bundles autoconfigure + snakeyaml + jackson-databind for users who want file-based config out of the box
- YAML test resources added to incubator/src/test/resources (ViewConfig tests still need them)
Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
…toconfigure module

Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
- Delete fileconfig tests from src/test/ (they were moved to testDeclarativeConfig
  in the previous commit but deletions were not staged)
- Fix ViewConfig/ViewConfigCustomizer javadoc: replace broken {@link} cross-module
  reference to DeclarativeConfigurationParser with {@code} (class moved to
  autoconfigure module which is not a main-scope dep of incubator)
- Delete incubator META-INF/services ComponentProvider registration (ServiceResourceDetector
  moved to autoconfigure module)
Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
…o testConvertToModel

- NoSharedInternalCodeTest: skip check when jar has no OpenTelemetry classes;
  autoconfigure-config is a dependency-only convenience module with no Java sources
- api/incubator testConvertToModel: add snakeyaml-engine to runtime deps;
  DeclarativeConfigurationParser (now in autoconfigure) uses snakeyaml internally
  but autoconfigure declares it compileOnly so it doesn't flow transitively
Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 9, 2026

Codecov Report

❌ Patch coverage is 89.47368% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.29%. Comparing base (1e0ddc6) to head (d6ba0ff).

Files with missing lines Patch % Lines
...incubator/fileconfig/DeclarativeConfiguration.java 86.48% 4 Missing and 1 partial ⚠️
...nfigure/AutoConfiguredOpenTelemetrySdkBuilder.java 87.50% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main    #8270      +/-   ##
============================================
- Coverage     90.29%   90.29%   -0.01%     
- Complexity     7656     7657       +1     
============================================
  Files           844      845       +1     
  Lines         23071    23081      +10     
  Branches       2311     2311              
============================================
+ Hits          20832    20841       +9     
  Misses         1521     1521              
- Partials        718      719       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@zeitlinger zeitlinger marked this pull request as ready for review April 9, 2026 13:27
@zeitlinger zeitlinger requested a review from a team as a code owner April 9, 2026 13:27
…urce package-private

Both were public but only used within the autoconfigure module. ResourceFactory
(different package, same module) now uses ResourceConfiguration.createEnvironmentResource
and inlines the property name string instead.
Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
Signed-off-by: Gregor Zeitlinger <gregor.zeitlinger@grafana.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant