Skip to content

Commit da63cef

Browse files
committed
Fixes for @nullable
Converters stored in a single flat map Exception thrown when converter not found
1 parent ad56046 commit da63cef

File tree

4 files changed

+79
-31
lines changed

4 files changed

+79
-31
lines changed

instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricInfo.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public enum Type {
2828
private final String metricName; // used as Instrument name
2929
@Nullable private final String description;
3030
@Nullable private final String sourceUnit;
31-
@Nullable private final String unit;
31+
private final String unit;
3232
private final Type type;
3333

3434
/**
@@ -44,7 +44,7 @@ public MetricInfo(
4444
String metricName,
4545
@Nullable String description,
4646
@Nullable String sourceUnit,
47-
@Nullable String unit,
47+
String unit,
4848
@Nullable Type type) {
4949
this.metricName = metricName;
5050
this.description = description;
@@ -67,7 +67,6 @@ public String getSourceUnit() {
6767
return sourceUnit;
6868
}
6969

70-
@Nullable
7170
public String getUnit() {
7271
return unit;
7372
}

instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/MetricRegistrar.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ void enrollExtractor(
8787
// CHECKSTYLE:ON
8888
LongCounterBuilder builder = meter.counterBuilder(metricName);
8989
Optional.ofNullable(description).ifPresent(builder::setDescription);
90-
Optional.ofNullable(unit).ifPresent(builder::setUnit);
90+
builder.setUnit(unit);
9191

9292
if (recordDoubleValue) {
9393
builder.ofDoubles().buildWithCallback(doubleTypeCallback(extractor, unitConverter));
@@ -104,7 +104,7 @@ void enrollExtractor(
104104
// CHECKSTYLE:ON
105105
LongUpDownCounterBuilder builder = meter.upDownCounterBuilder(metricName);
106106
Optional.ofNullable(description).ifPresent(builder::setDescription);
107-
Optional.ofNullable(unit).ifPresent(builder::setUnit);
107+
builder.setUnit(unit);
108108

109109
if (recordDoubleValue) {
110110
builder.ofDoubles().buildWithCallback(doubleTypeCallback(extractor, unitConverter));
@@ -121,7 +121,7 @@ void enrollExtractor(
121121
// CHECKSTYLE:ON
122122
DoubleGaugeBuilder builder = meter.gaugeBuilder(metricName);
123123
Optional.ofNullable(description).ifPresent(builder::setDescription);
124-
Optional.ofNullable(unit).ifPresent(builder::setUnit);
124+
builder.setUnit(unit);
125125

126126
if (recordDoubleValue) {
127127
builder.buildWithCallback(doubleTypeCallback(extractor, unitConverter));

instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/engine/unit/UnitConverterFactory.java

+30-13
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@
1212
import javax.annotation.Nullable;
1313

1414
public class UnitConverterFactory {
15-
16-
private static final Map<String, Map<String, UnitConverter>> conversionMappings = new HashMap<>();
15+
private static final Map<String, UnitConverter> conversionMappings = new HashMap<>();
1716

1817
static {
1918
registerConverter("ms", "s", value -> value.doubleValue() / TimeUnit.SECONDS.toMillis(1), true);
@@ -22,31 +21,49 @@ public class UnitConverterFactory {
2221

2322
private UnitConverterFactory() {}
2423

25-
public static UnitConverter getConverter(@Nullable String fromUnit, @Nullable String toUnit) {
26-
if (fromUnit == null || toUnit == null) {
27-
return null;
24+
@Nullable
25+
public static UnitConverter getConverter(@Nullable String sourceUnit, String targetUnit) {
26+
if (targetUnit.isEmpty()) {
27+
throw new IllegalArgumentException("Non empty targetUnit must be provided");
2828
}
2929

30-
Map<String, UnitConverter> converters = conversionMappings.get(fromUnit);
31-
if (converters == null) {
30+
if (sourceUnit == null || sourceUnit.isEmpty()) {
31+
// No conversion is needed
3232
return null;
3333
}
3434

35-
return converters.get(toUnit);
35+
String converterKey = getConverterKey(sourceUnit, targetUnit);
36+
UnitConverter converter = conversionMappings.get(converterKey);
37+
if (converter == null) {
38+
throw new IllegalStateException(
39+
"No [" + sourceUnit + "] to [" + targetUnit + "] unit converter");
40+
}
41+
42+
return converter;
3643
}
3744

3845
public static void registerConverter(
3946
String sourceUnit,
4047
String targetUnit,
4148
Function<Number, Number> convertingFunction,
4249
boolean convertToDouble) {
43-
Map<String, UnitConverter> converters =
44-
conversionMappings.computeIfAbsent(sourceUnit, k -> new HashMap<>());
50+
if (sourceUnit.isEmpty()) {
51+
throw new IllegalArgumentException("Non empty sourceUnit must be provided");
52+
}
53+
if (targetUnit.isEmpty()) {
54+
throw new IllegalArgumentException("Non empty targetUnit must be provided");
55+
}
56+
57+
String converterKey = getConverterKey(sourceUnit, targetUnit);
4558

46-
if (converters.containsKey(targetUnit)) {
59+
if (conversionMappings.containsKey(converterKey)) {
4760
throw new IllegalArgumentException(
48-
"Converter from " + sourceUnit + " to " + targetUnit + " already registered");
61+
"Converter from [" + sourceUnit + "] to [" + targetUnit + "] already registered");
4962
}
50-
converters.put(targetUnit, new UnitConverter(convertingFunction, convertToDouble));
63+
conversionMappings.put(converterKey, new UnitConverter(convertingFunction, convertToDouble));
64+
}
65+
66+
private static String getConverterKey(String sourceUnit, String targetUnit) {
67+
return sourceUnit + "->" + targetUnit;
5168
}
5269
}

instrumentation/jmx-metrics/library/src/test/java/io/opentelemetry/instrumentation/jmx/engine/unit/UnitConverterFactoryTest.java

+44-12
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,16 @@
55

66
package io.opentelemetry.instrumentation.jmx.engine.unit;
77

8+
import static org.assertj.core.api.Assertions.assertThat;
89
import static org.junit.jupiter.api.Assertions.assertEquals;
910
import static org.junit.jupiter.api.Assertions.assertFalse;
1011
import static org.junit.jupiter.api.Assertions.assertNull;
12+
import static org.junit.jupiter.api.Assertions.assertThrows;
1113
import static org.junit.jupiter.api.Assertions.assertTrue;
1214

13-
import java.util.stream.Stream;
1415
import org.junit.jupiter.api.Test;
1516
import org.junit.jupiter.params.ParameterizedTest;
16-
import org.junit.jupiter.params.provider.Arguments;
1717
import org.junit.jupiter.params.provider.CsvSource;
18-
import org.junit.jupiter.params.provider.MethodSource;
1918

2019
class UnitConverterFactoryTest {
2120

@@ -62,18 +61,51 @@ void shouldSupportCustomConverter() {
6261
}
6362

6463
@ParameterizedTest
65-
@MethodSource("provideUnitsForMissingConverter")
66-
void shouldHandleMissingConverter(String sourceUnit, String targetUnit) {
64+
@CsvSource({
65+
"--, --",
66+
"ms, non-existing",
67+
"non-existing, s",
68+
})
69+
void shouldHandleNonExistingConverter(String sourceUnit, String targetUnit) {
70+
IllegalStateException exception =
71+
assertThrows(
72+
IllegalStateException.class,
73+
() -> UnitConverterFactory.getConverter(sourceUnit, targetUnit));
74+
assertEquals(
75+
"No [" + sourceUnit + "] to [" + targetUnit + "] unit converter", exception.getMessage());
76+
}
77+
78+
@ParameterizedTest
79+
@CsvSource({
80+
", s", // null -> "s"
81+
"'', s", // "" -> "s"
82+
})
83+
void shouldSkipConversionWhenSourceUnitNotSpecified(String sourceUnit, String targetUnit) {
6784
UnitConverter converter = UnitConverterFactory.getConverter(sourceUnit, targetUnit);
6885
assertNull(converter);
6986
}
7087

71-
private static Stream<Arguments> provideUnitsForMissingConverter() {
72-
return Stream.of(
73-
Arguments.of(null, null),
74-
Arguments.of("ms", null),
75-
Arguments.of("ms", ""),
76-
Arguments.of("ms", "--"),
77-
Arguments.of("--", "--"));
88+
@ParameterizedTest
89+
@CsvSource({
90+
"'', By", "By, ''",
91+
})
92+
void shouldThrowExceptionWhenRegisteringConverterWithAnyUnitEmpty(
93+
String sourceUnit, String targetUnit) {
94+
IllegalArgumentException exception =
95+
assertThrows(
96+
IllegalArgumentException.class,
97+
() ->
98+
UnitConverterFactory.registerConverter(
99+
sourceUnit, targetUnit, (value) -> 0, false));
100+
assertThat(exception.getMessage()).matches("Non empty .+Unit must be provided");
101+
}
102+
103+
@Test
104+
void shouldNotAllowRegisteringAgainAlreadyExistingConverter() {
105+
IllegalArgumentException exception =
106+
assertThrows(
107+
IllegalArgumentException.class,
108+
() -> UnitConverterFactory.registerConverter("ms", "s", (v) -> 0, false));
109+
assertEquals("Converter from [ms] to [s] already registered", exception.getMessage());
78110
}
79111
}

0 commit comments

Comments
 (0)