Skip to content

Commit c872957

Browse files
committed
Revert ObjectMapper to DeclarativeConfiguration with copy-paste docs
Per maintainer feedback, avoid exposing ObjectMapper API (internal or public). Instead, document configuration for copy-paste approach. - Move ObjectMapper back from YamlObjectMapper to DeclarativeConfiguration - Add "For Implementers" section in javadoc with setup example - Add field javadoc explaining config and referencing class docs - Remove YamlObjectMapper.java
1 parent 258835a commit c872957

File tree

2 files changed

+61
-55
lines changed

2 files changed

+61
-55
lines changed

sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfiguration.java

Lines changed: 61 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,17 @@
55

66
package io.opentelemetry.sdk.extension.incubator.fileconfig;
77

8+
import com.fasterxml.jackson.annotation.JsonSetter;
9+
import com.fasterxml.jackson.annotation.Nulls;
810
import com.fasterxml.jackson.core.type.TypeReference;
11+
import com.fasterxml.jackson.databind.ObjectMapper;
912
import io.opentelemetry.api.incubator.config.DeclarativeConfigException;
1013
import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties;
1114
import io.opentelemetry.common.ComponentLoader;
1215
import io.opentelemetry.sdk.OpenTelemetrySdk;
1316
import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper;
1417
import io.opentelemetry.sdk.autoconfigure.spi.internal.AutoConfigureListener;
1518
import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider;
16-
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.YamlObjectMapper;
1719
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel;
1820
import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SamplerModel;
1921
import io.opentelemetry.sdk.internal.ExtendedOpenTelemetrySdk;
@@ -51,6 +53,31 @@
5153
* <a
5254
* href="https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/data-model.md#yaml-file-format">YAML
5355
* configuration file</a>.
56+
*
57+
* <h2>For Implementers</h2>
58+
*
59+
* <p>External consumers needing to parse OpenTelemetry YAML configuration files should use the same
60+
* Jackson ObjectMapper configuration for compatibility. This configuration is intentionally not
61+
* exposed as API to avoid coupling. Instead, copy the following setup:
62+
*
63+
* <pre>{@code
64+
* ObjectMapper mapper = new ObjectMapper()
65+
* // Create empty object instances for keys which are present but have null values
66+
* .setDefaultSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY));
67+
* // Boxed primitives which are present but have null values should be set to null,
68+
* // rather than empty instances
69+
* mapper.configOverride(String.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET));
70+
* mapper.configOverride(Integer.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET));
71+
* mapper.configOverride(Double.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET));
72+
* mapper.configOverride(Boolean.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET));
73+
* }</pre>
74+
*
75+
* <p><b>Why this configuration:</b>
76+
*
77+
* <ul>
78+
* <li>Default behavior creates empty objects for null values to match YAML schema expectations
79+
* <li>Boxed primitives remain null to distinguish between absent and explicitly null values
80+
* </ul>
5481
*/
5582
public final class DeclarativeConfiguration {
5683

@@ -60,6 +87,35 @@ public final class DeclarativeConfiguration {
6087
private static final ComponentLoader DEFAULT_COMPONENT_LOADER =
6188
ComponentLoader.forClassLoader(DeclarativeConfigProperties.class.getClassLoader());
6289

90+
/**
91+
* ObjectMapper configured for YAML declarative configuration parsing.
92+
*
93+
* <p>Configuration:
94+
*
95+
* <ul>
96+
* <li>Default: Creates empty objects for present keys with null values
97+
* <li>Boxed primitives (String, Integer, Double, Boolean): Remain null when null
98+
* </ul>
99+
*
100+
* <p>External consumers needing compatible parsing should copy this configuration. See class
101+
* javadoc for details and code example.
102+
*/
103+
// Visible for testing
104+
static final ObjectMapper MAPPER;
105+
106+
static {
107+
MAPPER =
108+
new ObjectMapper()
109+
// Create empty object instances for keys which are present but have null values
110+
.setDefaultSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY));
111+
// Boxed primitives which are present but have null values should be set to null, rather than
112+
// empty instances
113+
MAPPER.configOverride(String.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET));
114+
MAPPER.configOverride(Integer.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET));
115+
MAPPER.configOverride(Double.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET));
116+
MAPPER.configOverride(Boolean.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET));
117+
}
118+
63119
private DeclarativeConfiguration() {}
64120

65121
/**
@@ -140,8 +196,7 @@ public static OpenTelemetryConfigurationModel parse(InputStream configuration) {
140196
static OpenTelemetryConfigurationModel parse(
141197
InputStream configuration, Map<String, String> environmentVariables) {
142198
Object yamlObj = loadYaml(configuration, environmentVariables);
143-
return YamlObjectMapper.getInstance()
144-
.convertValue(yamlObj, OpenTelemetryConfigurationModel.class);
199+
return MAPPER.convertValue(yamlObj, OpenTelemetryConfigurationModel.class);
145200
}
146201

147202
// Visible for testing
@@ -175,8 +230,7 @@ public static DeclarativeConfigProperties toConfigProperties(InputStream configu
175230
static DeclarativeConfigProperties toConfigProperties(
176231
Object model, ComponentLoader componentLoader) {
177232
Map<String, Object> configurationMap =
178-
YamlObjectMapper.getInstance()
179-
.convertValue(model, new TypeReference<Map<String, Object>>() {});
233+
MAPPER.convertValue(model, new TypeReference<Map<String, Object>>() {});
180234
if (configurationMap == null) {
181235
configurationMap = Collections.emptyMap();
182236
}
@@ -197,10 +251,8 @@ public static Sampler createSampler(DeclarativeConfigProperties genericSamplerMo
197251
YamlDeclarativeConfigProperties yamlDeclarativeConfigProperties =
198252
requireYamlDeclarativeConfigProperties(genericSamplerModel);
199253
SamplerModel samplerModel =
200-
YamlObjectMapper.getInstance()
201-
.convertValue(
202-
DeclarativeConfigProperties.toMap(yamlDeclarativeConfigProperties),
203-
SamplerModel.class);
254+
MAPPER.convertValue(
255+
DeclarativeConfigProperties.toMap(yamlDeclarativeConfigProperties), SamplerModel.class);
204256
return createAndMaybeCleanup(
205257
SamplerFactory.getInstance(),
206258
DeclarativeConfigContext.create(yamlDeclarativeConfigProperties.getComponentLoader()),

sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/internal/YamlObjectMapper.java

Lines changed: 0 additions & 46 deletions
This file was deleted.

0 commit comments

Comments
 (0)