Skip to content

Commit 7f77708

Browse files
committed
fix for flagsmith string to double conversion issue(#1557)
Signed-off-by: Kush Batra <[email protected]>
1 parent 0b720f3 commit 7f77708

File tree

3 files changed

+87
-6
lines changed

3 files changed

+87
-6
lines changed

providers/flagd/src/main/java/dev/openfeature/contrib/providers/flagd/FlagdProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ private void onProviderEvent(FlagdProviderEvent flagdProviderEvent) {
210210
onConfigurationChanged(flagdProviderEvent);
211211
break;
212212
}
213-
// intentional fall through
213+
// intentional fall through
214214
case PROVIDER_READY:
215215
/*
216216
* Sync metadata is used to enrich the context, and is immutable in flagd,

providers/flagsmith/src/main/java/dev.openfeature.contrib.providers.flagsmith/FlagsmithProvider.java

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -180,19 +180,53 @@ private <T> ProviderEvaluation<T> buildEvaluation(
180180
* @param expectedType the type we expect for this value
181181
* @param <T> the type we want to convert to
182182
* @return A converted object
183+
* @throws TypeMismatchError if the value cannot be converted to the expected type
183184
*/
185+
@SuppressWarnings("unchecked")
184186
private <T> T convertValue(Object value, Class<?> expectedType) {
185187
boolean isPrimitive = expectedType == Boolean.class
186188
|| expectedType == String.class
187189
|| expectedType == Integer.class
188190
|| expectedType == Double.class;
189-
T flagValue = isPrimitive ? (T) value : (T) objectToValue(value);
191+
Object flagValue;
192+
String message = "Flag value had an unexpected type (" + (value != null ? value.getClass() : "null")
193+
+ "), expected (" + expectedType + ").";
194+
if (isPrimitive) {
195+
if (expectedType == Double.class) {
196+
if (value instanceof Double) {
197+
flagValue = value;
198+
} else if (value instanceof String) {
199+
try {
200+
flagValue = Double.parseDouble((String) value);
201+
} catch (NumberFormatException e) {
202+
throw new TypeMismatchError("Flag value string could not be parsed as Double: " + value);
203+
}
204+
} else {
205+
throw new TypeMismatchError(message);
206+
}
207+
} else if (expectedType == Integer.class) {
208+
if (value instanceof Integer) {
209+
flagValue = value;
210+
} else if (value instanceof String) {
211+
try {
212+
flagValue = Integer.parseInt((String) value);
213+
} catch (NumberFormatException e) {
214+
throw new TypeMismatchError("Flag value string could not be parsed as Integer: " + value);
215+
}
216+
} else {
217+
throw new TypeMismatchError(message);
218+
}
219+
} else {
220+
flagValue = value;
221+
}
222+
} else {
223+
flagValue = objectToValue(value);
224+
}
190225

191-
if (flagValue.getClass() != expectedType) {
192-
throw new TypeMismatchError(
193-
"Flag value had an unexpected type " + flagValue.getClass() + ", expected " + expectedType + ".");
226+
if (!expectedType.isInstance(flagValue)) {
227+
throw new TypeMismatchError(message);
194228
}
195-
return flagValue;
229+
return (T) flagValue;
196230
}
197231

198232
/**

providers/flagsmith/src/test/java/dev.openfeature.contrib.providers.flagsmith/FlagsmithProviderTest.java

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,53 @@ void tearDown() throws IOException {
159159
mockFlagsmithErrorServer.shutdown();
160160
}
161161

162+
@ParameterizedTest
163+
@MethodSource("convertValueArguments")
164+
void testConvertValue(Object input, Class<?> expectedType, Object expected) throws Exception {
165+
var method = flagsmithProvider.getClass().getDeclaredMethod("convertValue", Object.class, Class.class);
166+
method.setAccessible(true);
167+
Object result = method.invoke(flagsmithProvider, input, expectedType);
168+
assertEquals(expected, result);
169+
}
170+
171+
private static Stream<Arguments> convertValueArguments() {
172+
return Stream.of(
173+
Arguments.of(true, Boolean.class, true),
174+
Arguments.of("test", String.class, "test"),
175+
Arguments.of(123, Integer.class, 123),
176+
Arguments.of("123", Integer.class, 123),
177+
Arguments.of(3.14, Double.class, 3.14),
178+
Arguments.of("3.14", Double.class, 3.14));
179+
}
180+
181+
@Test
182+
void testConvertValueThrowsTypeMismatchErrorForInvalidInteger() throws Exception {
183+
var method = flagsmithProvider.getClass().getDeclaredMethod("convertValue", Object.class, Class.class);
184+
method.setAccessible(true);
185+
assertThrows(dev.openfeature.sdk.exceptions.TypeMismatchError.class, () -> {
186+
try {
187+
method.invoke(flagsmithProvider, "abc", Integer.class);
188+
} catch (java.lang.reflect.InvocationTargetException e) {
189+
// Rethrow the actual exception thrown by convertValue
190+
throw e.getCause();
191+
}
192+
});
193+
}
194+
195+
@Test
196+
void testConvertValueThrowsTypeMismatchErrorForInvalidDouble() throws Exception {
197+
var method = flagsmithProvider.getClass().getDeclaredMethod("convertValue", Object.class, Class.class);
198+
method.setAccessible(true);
199+
assertThrows(dev.openfeature.sdk.exceptions.TypeMismatchError.class, () -> {
200+
try {
201+
method.invoke(flagsmithProvider, "abc", Double.class);
202+
} catch (java.lang.reflect.InvocationTargetException e) {
203+
// Rethrow the actual exception thrown by convertValue
204+
throw e.getCause();
205+
}
206+
});
207+
}
208+
162209
@Test
163210
void shouldInitializeProviderWhenAllOptionsSet() {
164211
HashMap<String, String> headers = new HashMap<String, String>() {

0 commit comments

Comments
 (0)