diff --git a/pom.xml b/pom.xml
index 25104ff13..a51d074cd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -63,6 +63,18 @@
2.0.7
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+ 2.15.2
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.15.2
+
+
org.mockito
@@ -152,6 +164,13 @@
4.2.0
test
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ 2.15.2
+ test
+
diff --git a/src/main/java/dev/openfeature/sdk/ImmutableMetadata.java b/src/main/java/dev/openfeature/sdk/ImmutableMetadata.java
index 1bc130b42..a9dd93fe0 100644
--- a/src/main/java/dev/openfeature/sdk/ImmutableMetadata.java
+++ b/src/main/java/dev/openfeature/sdk/ImmutableMetadata.java
@@ -1,5 +1,7 @@
package dev.openfeature.sdk;
+import com.fasterxml.jackson.annotation.JsonGetter;
+import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.extern.slf4j.Slf4j;
import java.util.HashMap;
@@ -13,10 +15,17 @@
public class ImmutableMetadata {
private final Map metadata;
- private ImmutableMetadata(Map metadata) {
+ private ImmutableMetadata(@JsonProperty("metadata") Map metadata) {
this.metadata = metadata;
}
+ // This is required for serialization support
+ @SuppressWarnings({"PMD.UnusedPrivateMethod"})
+ @JsonGetter("metadata")
+ private Map getMetadata() {
+ return this.metadata;
+ }
+
/**
* Retrieve a {@link String} value for the given key. A {@code null} value is returned if the key does not exist
* or if the value is of a different type.
diff --git a/src/main/java/dev/openfeature/sdk/ProviderEvaluation.java b/src/main/java/dev/openfeature/sdk/ProviderEvaluation.java
index 42441a8e7..b75eae266 100644
--- a/src/main/java/dev/openfeature/sdk/ProviderEvaluation.java
+++ b/src/main/java/dev/openfeature/sdk/ProviderEvaluation.java
@@ -2,11 +2,14 @@
import lombok.Builder;
import lombok.Data;
+import lombok.extern.jackson.Jacksonized;
import javax.annotation.Nullable;
@SuppressWarnings("checkstyle:MissingJavadocType")
-@Data @Builder
+@Data
+@Builder
+@Jacksonized
public class ProviderEvaluation implements BaseEvaluation {
T value;
@Nullable String variant;
diff --git a/src/test/java/dev/openfeature/sdk/FlagMetadataTest.java b/src/test/java/dev/openfeature/sdk/ImmutableMetadataTest.java
similarity index 54%
rename from src/test/java/dev/openfeature/sdk/FlagMetadataTest.java
rename to src/test/java/dev/openfeature/sdk/ImmutableMetadataTest.java
index c300daa05..b91d68492 100644
--- a/src/test/java/dev/openfeature/sdk/FlagMetadataTest.java
+++ b/src/test/java/dev/openfeature/sdk/ImmutableMetadataTest.java
@@ -1,11 +1,13 @@
package dev.openfeature.sdk;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
-class FlagMetadataTest {
+class ImmutableMetadataTest {
@Test
@DisplayName("Test metadata payload construction and retrieval")
@@ -61,4 +63,39 @@ public void notfound_error_validation() {
// then
assertThat(flagMetadata.getBoolean("string")).isNull();
}
+
+ @Test
+ @DisplayName("Make sure class is se/deserializable")
+ public void test_serialize_deserialization() throws JsonProcessingException {
+ // given
+ ImmutableMetadata original = ImmutableMetadata.builder()
+ .addString("string", "string")
+ .addInteger("integer", 1)
+ .addLong("long", Long.MAX_VALUE)
+ .addFloat("float", Float.MAX_VALUE)
+ .addDouble("double", Double.MAX_VALUE)
+ .addBoolean("boolean", Boolean.FALSE)
+ .build();
+
+
+ final ObjectMapper mapper = new ObjectMapper();
+
+ // when
+ final String json = mapper.writeValueAsString(original);
+ final ImmutableMetadata converted = mapper.readValue(json, ImmutableMetadata.class);
+
+ // then
+ assertThat(json).isEqualTo("{\"metadata\":{\"boolean\":false,\"string\":\"string\"," +
+ "\"double\":1.7976931348623157E308,\"integer\":1,\"float\":3.4028235E38,\"long\":9223372036854775807}}");
+
+ assertThat(converted.getValue("string", String.class)).isEqualTo(original.getString("string"));
+ assertThat(converted.getValue("integer", Integer.class)).isEqualTo(original.getInteger("integer"));
+ assertThat(converted.getValue("boolean", Boolean.class)).isEqualTo(original.getBoolean("boolean"));
+ assertThat(converted.getValue("long", Long.class)).isEqualTo(original.getValue("long", Long.class));
+ assertThat(converted.getValue("double", Number.class)).isEqualTo(original.getValue("double", Number.class));
+
+ // float get converted to double, hence representation comparison
+ assertThat(converted.getValue("float", Double.class).toString())
+ .isEqualTo(original.getValue("float", Float.class).toString());
+ }
}
diff --git a/src/test/java/dev/openfeature/sdk/ProviderEvaluationTest.java b/src/test/java/dev/openfeature/sdk/ProviderEvaluationTest.java
new file mode 100644
index 000000000..5eca7be45
--- /dev/null
+++ b/src/test/java/dev/openfeature/sdk/ProviderEvaluationTest.java
@@ -0,0 +1,46 @@
+package dev.openfeature.sdk;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class ProviderEvaluationTest {
+
+ @Test
+ @DisplayName("Provider evaluation must support JSON se/deserialization")
+ public void test_serialization_deserialization() throws IOException {
+ // given
+ final ProviderEvaluation original = ProviderEvaluation.builder()
+ .reason(Reason.STATIC.toString())
+ .variant("Default")
+ .value("StringValue")
+ .flagMetadata(ImmutableMetadata.builder()
+ .addString("key", "value")
+ .addInteger("integer", 10)
+ .build()
+ )
+ .build();
+
+
+ // when
+ final String json = new ObjectMapper().writer().writeValueAsString(original);
+ final ObjectMapper objectMapper = new ObjectMapper();
+ final Reader reader = new StringReader(json);
+ final ProviderEvaluation converted = objectMapper.readValue(reader, ProviderEvaluation.class);
+
+ // then
+ assertThat(converted.getReason()).isEqualTo(original.getReason());
+ assertThat(converted.getVariant()).isEqualTo(original.getVariant());
+ assertThat(converted.getValue()).isEqualTo(original.getValue());
+ assertThat(converted.getFlagMetadata().getString("key"))
+ .isEqualTo(original.getFlagMetadata().getString("key"));
+ assertThat(converted.getFlagMetadata().getInteger("integer"))
+ .isEqualTo(original.getFlagMetadata().getInteger("integer"));
+ }
+}
\ No newline at end of file