diff --git a/providers/flagsmith/src/main/java/dev.openfeature.contrib.providers.flagsmith/FlagsmithProvider.java b/providers/flagsmith/src/main/java/dev.openfeature.contrib.providers.flagsmith/FlagsmithProvider.java index 47a5bf0f8..91755a204 100644 --- a/providers/flagsmith/src/main/java/dev.openfeature.contrib.providers.flagsmith/FlagsmithProvider.java +++ b/providers/flagsmith/src/main/java/dev.openfeature.contrib.providers.flagsmith/FlagsmithProvider.java @@ -180,19 +180,42 @@ private ProviderEvaluation buildEvaluation( * @param expectedType the type we expect for this value * @param the type we want to convert to * @return A converted object + * @throws TypeMismatchError if the value cannot be converted to the expected type */ + @SuppressWarnings("unchecked") private T convertValue(Object value, Class expectedType) { boolean isPrimitive = expectedType == Boolean.class || expectedType == String.class || expectedType == Integer.class || expectedType == Double.class; - T flagValue = isPrimitive ? (T) value : (T) objectToValue(value); - if (flagValue.getClass() != expectedType) { - throw new TypeMismatchError( - "Flag value had an unexpected type " + flagValue.getClass() + ", expected " + expectedType + "."); + Object flagValue; + if (isPrimitive) { + if (expectedType == Double.class) { + if (value instanceof Double) { + flagValue = value; + } else if (value instanceof String) { + try { + flagValue = Double.parseDouble((String) value); + } catch (NumberFormatException e) { + throw new TypeMismatchError("Flag value string could not be parsed as Double: " + value); + } + } else { + throw new TypeMismatchError("Flag value had an unexpected type " + + (value != null ? value.getClass() : "null") + ", expected " + expectedType + "."); + } + } else { + flagValue = value; + } + } else { + flagValue = objectToValue(value); + } + + if (!expectedType.isInstance(flagValue)) { + throw new TypeMismatchError("Flag value had an unexpected type " + + (flagValue != null ? flagValue.getClass() : "null" + ", expected " + expectedType + ".")); } - return flagValue; + return (T) flagValue; } /** diff --git a/providers/flagsmith/src/test/java/dev.openfeature.contrib.providers.flagsmith/FlagsmithProviderTest.java b/providers/flagsmith/src/test/java/dev.openfeature.contrib.providers.flagsmith/FlagsmithProviderTest.java index 83e60c0d0..f44cbaf3e 100644 --- a/providers/flagsmith/src/test/java/dev.openfeature.contrib.providers.flagsmith/FlagsmithProviderTest.java +++ b/providers/flagsmith/src/test/java/dev.openfeature.contrib.providers.flagsmith/FlagsmithProviderTest.java @@ -159,6 +159,24 @@ void tearDown() throws IOException { mockFlagsmithErrorServer.shutdown(); } + @ParameterizedTest + @MethodSource("convertValueArguments") + void testConvertValue(Object input, Class expectedType, Object expected) throws Exception { + var method = flagsmithProvider.getClass().getDeclaredMethod("convertValue", Object.class, Class.class); + method.setAccessible(true); + Object result = method.invoke(flagsmithProvider, input, expectedType); + assertEquals(expected, result); + } + + private static Stream convertValueArguments() { + return Stream.of( + Arguments.of(true, Boolean.class, true), + Arguments.of("test", String.class, "test"), + Arguments.of(123, Integer.class, 123), + Arguments.of(3.14, Double.class, 3.14), + Arguments.of("3.14", Double.class, 3.14)); + } + @Test void shouldInitializeProviderWhenAllOptionsSet() { HashMap headers = new HashMap() {