diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfiguration.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfiguration.java index 6e67bd0bdb4..6fceb43ec43 100644 --- a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfiguration.java +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/DeclarativeConfiguration.java @@ -5,10 +5,7 @@ package io.opentelemetry.sdk.extension.incubator.fileconfig; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import io.opentelemetry.api.incubator.config.DeclarativeConfigException; import io.opentelemetry.api.incubator.config.DeclarativeConfigProperties; import io.opentelemetry.common.ComponentLoader; @@ -16,6 +13,7 @@ import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper; import io.opentelemetry.sdk.autoconfigure.spi.internal.AutoConfigureListener; import io.opentelemetry.sdk.autoconfigure.spi.internal.ComponentProvider; +import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.YamlObjectMapper; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.OpenTelemetryConfigurationModel; import io.opentelemetry.sdk.extension.incubator.fileconfig.internal.model.SamplerModel; import io.opentelemetry.sdk.internal.ExtendedOpenTelemetrySdk; @@ -62,22 +60,6 @@ public final class DeclarativeConfiguration { private static final ComponentLoader DEFAULT_COMPONENT_LOADER = ComponentLoader.forClassLoader(DeclarativeConfigProperties.class.getClassLoader()); - // Visible for testing - static final ObjectMapper MAPPER; - - static { - MAPPER = - new ObjectMapper() - // Create empty object instances for keys which are present but have null values - .setDefaultSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY)); - // Boxed primitives which are present but have null values should be set to null, rather than - // empty instances - MAPPER.configOverride(String.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET)); - MAPPER.configOverride(Integer.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET)); - MAPPER.configOverride(Double.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET)); - MAPPER.configOverride(Boolean.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET)); - } - private DeclarativeConfiguration() {} /** @@ -158,7 +140,8 @@ public static OpenTelemetryConfigurationModel parse(InputStream configuration) { static OpenTelemetryConfigurationModel parse( InputStream configuration, Map environmentVariables) { Object yamlObj = loadYaml(configuration, environmentVariables); - return MAPPER.convertValue(yamlObj, OpenTelemetryConfigurationModel.class); + return YamlObjectMapper.getInstance() + .convertValue(yamlObj, OpenTelemetryConfigurationModel.class); } // Visible for testing @@ -192,7 +175,8 @@ public static DeclarativeConfigProperties toConfigProperties(InputStream configu static DeclarativeConfigProperties toConfigProperties( Object model, ComponentLoader componentLoader) { Map configurationMap = - MAPPER.convertValue(model, new TypeReference>() {}); + YamlObjectMapper.getInstance() + .convertValue(model, new TypeReference>() {}); if (configurationMap == null) { configurationMap = Collections.emptyMap(); } @@ -213,8 +197,10 @@ public static Sampler createSampler(DeclarativeConfigProperties genericSamplerMo YamlDeclarativeConfigProperties yamlDeclarativeConfigProperties = requireYamlDeclarativeConfigProperties(genericSamplerModel); SamplerModel samplerModel = - MAPPER.convertValue( - DeclarativeConfigProperties.toMap(yamlDeclarativeConfigProperties), SamplerModel.class); + YamlObjectMapper.getInstance() + .convertValue( + DeclarativeConfigProperties.toMap(yamlDeclarativeConfigProperties), + SamplerModel.class); return createAndMaybeCleanup( SamplerFactory.getInstance(), DeclarativeConfigContext.create(yamlDeclarativeConfigProperties.getComponentLoader()), diff --git a/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/internal/YamlObjectMapper.java b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/internal/YamlObjectMapper.java new file mode 100644 index 00000000000..a14dc53174f --- /dev/null +++ b/sdk-extensions/incubator/src/main/java/io/opentelemetry/sdk/extension/incubator/fileconfig/internal/YamlObjectMapper.java @@ -0,0 +1,46 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.extension.incubator.fileconfig.internal; + +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.Nulls; +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * Provides a configured {@link ObjectMapper} for YAML declarative configuration parsing. + * + *

This class is internal and is hence not for public use. Its APIs are unstable and can change + * at any time. + */ +public final class YamlObjectMapper { + + private static final ObjectMapper INSTANCE; + + static { + INSTANCE = + new ObjectMapper() + // Create empty object instances for keys which are present but have null values + .setDefaultSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY)); + // Boxed primitives which are present but have null values should be set to null, rather than + // empty instances + INSTANCE.configOverride(String.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET)); + INSTANCE.configOverride(Integer.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET)); + INSTANCE.configOverride(Double.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET)); + INSTANCE.configOverride(Boolean.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.SET)); + } + + private YamlObjectMapper() {} + + /** + * Returns the configured {@link ObjectMapper} instance for parsing YAML declarative + * configuration. + * + * @return the configured ObjectMapper + */ + public static ObjectMapper getInstance() { + return INSTANCE; + } +}