[685] Fix the issue when deserializing a Map which has a wildcard value. Added tests for wildcards on map keys and values, lists and optional. Signed-off-by: James R. Perkins <jperkins@ibm.com>
diff --git a/src/main/java/org/eclipse/yasson/internal/deserializer/DeserializationModelCreator.java b/src/main/java/org/eclipse/yasson/internal/deserializer/DeserializationModelCreator.java index cebe6c3..6a6daca 100644 --- a/src/main/java/org/eclipse/yasson/internal/deserializer/DeserializationModelCreator.java +++ b/src/main/java/org/eclipse/yasson/internal/deserializer/DeserializationModelCreator.java
@@ -296,7 +296,7 @@ ClassCustomization.empty(), JustReturn.instance(), MAP_KEY_EVENTS); - ClassModel valueClassModel = jsonbContext.getMappingContext().getOrCreateClassModel(ReflectionUtils.getRawType(valueType)); + ClassModel valueClassModel = jsonbContext.getMappingContext().getOrCreateClassModel(ReflectionUtils.resolveRawType(chain, valueType)); ModelDeserializer<JsonParser> valueProcessor = typeProcessor(chain, valueType, valueClassModel.getClassCustomization(),
diff --git a/src/test/java/org/eclipse/yasson/serializers/TypeDeserializerOnContainersTest.java b/src/test/java/org/eclipse/yasson/serializers/TypeDeserializerOnContainersTest.java index 4b4d871..7cd1e3f 100644 --- a/src/test/java/org/eclipse/yasson/serializers/TypeDeserializerOnContainersTest.java +++ b/src/test/java/org/eclipse/yasson/serializers/TypeDeserializerOnContainersTest.java
@@ -79,19 +79,23 @@ // Container classes for testing public static class MapContainer { public Map<String, TestInterface> map; + public Map<?, ?> questionKeyMap; + public Map<String, ?> questionValueMap; } public static class ListContainer { public List<TestInterface> list; + public List<?> questionList; } public static class ArrayContainer { public TestInterface[] array; } + @SuppressWarnings("OptionalUsedAsFieldOrParameterType") public static class OptionalContainer { - @SuppressWarnings("OptionalUsedAsFieldOrParameterType") public Optional<TestInterface> optional; + public Optional<?> questionOptional; } public static class ByteArrayContainer { @@ -115,7 +119,7 @@ @Test public void testTypeDeserializerOnMapValues() { - final String json = "{\"map\":{\"key1\":{\"value\":\"value1\"},\"key2\":{\"value\":\"value2\"}}}"; + final String json = "{\"map\":{\"key1\":{\"value\":\"value1\"},\"key2\":{\"value\":\"value2\"}}, \"questionKeyMap\":{\"qKey1\":\"value1\",\"qKey2\":\"value2\"},\"questionValueMap\":{\"key1\":\"qValue1\",\"key2\":\"qValue2\"}}"; final MapContainer result = jsonb.fromJson(json, MapContainer.class); @@ -123,11 +127,21 @@ Assertions.assertEquals(2, result.map.size(), () -> String.format("Expected two entries got %s", result.map)); Assertions.assertEquals("DESERIALIZED:value1", result.map.get("key1").getValue()); Assertions.assertEquals("DESERIALIZED:value2", result.map.get("key2").getValue()); + + Assertions.assertNotNull(result.questionKeyMap); + Assertions.assertEquals(2, result.questionKeyMap.size(), () -> String.format("Expected two entries got %s", result.questionKeyMap)); + Assertions.assertEquals("value1", result.questionKeyMap.get("qKey1")); + Assertions.assertEquals("value2", result.questionKeyMap.get("qKey2")); + + Assertions.assertNotNull(result.questionValueMap); + Assertions.assertEquals(2, result.questionValueMap.size(), () -> String.format("Expected two entries got %s", result.questionValueMap)); + Assertions.assertEquals("qValue1", result.questionValueMap.get("key1")); + Assertions.assertEquals("qValue2", result.questionValueMap.get("key2")); } @Test public void testTypeDeserializerOnListElements() { - final String json = "{\"list\":[{\"value\":\"value1\"},{\"value\":\"value2\"}]}"; + final String json = "{\"list\":[{\"value\":\"value1\"},{\"value\":\"value2\"}], \"questionList\": [\"value1\", \"value2\"]}"; final ListContainer result = jsonb.fromJson(json, ListContainer.class); @@ -135,6 +149,11 @@ Assertions.assertEquals(2, result.list.size(), () -> String.format("Expected two entries got %s", result.list)); Assertions.assertEquals("DESERIALIZED:value1", result.list.get(0).getValue()); Assertions.assertEquals("DESERIALIZED:value2", result.list.get(1).getValue()); + + Assertions.assertNotNull(result.questionList); + Assertions.assertEquals(2, result.questionList.size(), () -> String.format("Expected two entries got %s", result.questionList)); + Assertions.assertEquals("value1", result.questionList.get(0)); + Assertions.assertEquals("value2", result.questionList.get(1)); } @Test @@ -151,13 +170,17 @@ @Test public void testTypeDeserializerOnOptionalValue() { - final String json = "{\"optional\":{\"value\":\"value1\"}}"; + final String json = "{\"optional\":{\"value\":\"value1\"},\"questionOptional\":\"value2\"}"; final OptionalContainer result = jsonb.fromJson(json, OptionalContainer.class); Assertions.assertNotNull(result.optional); Assertions.assertTrue(result.optional.isPresent(), "Expected value to be present, but the optional was empty."); Assertions.assertEquals("DESERIALIZED:value1", result.optional.get().getValue()); + + Assertions.assertNotNull(result.questionOptional); + Assertions.assertTrue(result.questionOptional.isPresent(), "Expected value to be present, but the optional was empty."); + Assertions.assertEquals("value2", result.questionOptional.get()); } @Test
diff --git a/src/test/java/org/eclipse/yasson/serializers/TypeSerializerOnContainersTest.java b/src/test/java/org/eclipse/yasson/serializers/TypeSerializerOnContainersTest.java index a3edc45..89f3ff2 100644 --- a/src/test/java/org/eclipse/yasson/serializers/TypeSerializerOnContainersTest.java +++ b/src/test/java/org/eclipse/yasson/serializers/TypeSerializerOnContainersTest.java
@@ -12,12 +12,19 @@ package org.eclipse.yasson.serializers; +import java.io.StringReader; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.function.Supplier; +import jakarta.json.Json; +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import jakarta.json.JsonReader; import jakarta.json.bind.Jsonb; import jakarta.json.bind.JsonbBuilder; +import jakarta.json.bind.JsonbException; import jakarta.json.bind.annotation.JsonbTypeSerializer; import jakarta.json.bind.serializer.JsonbSerializer; import jakarta.json.bind.serializer.SerializationContext; @@ -66,35 +73,43 @@ // Container classes for testing public static class MapContainer { - public Map<String, TestInterface> map; + public final Map<String, TestInterface> map; + public final Map<?, ?> questionKeyMap; + public final Map<String, ?> questionValueMap; - public MapContainer(Map<String, TestInterface> map) { + public MapContainer(final Map<String, TestInterface> map, final Map<?, ?> questionKeyMap, final Map<String, ?> questionValueMap) { this.map = map; + this.questionKeyMap = questionKeyMap; + this.questionValueMap = questionValueMap; } } public static class ListContainer { - public List<TestInterface> list; + public final List<TestInterface> list; + public final List<?> questionList; - public ListContainer(List<TestInterface> list) { + public ListContainer(final List<TestInterface> list, final List<?> questionList) { this.list = list; + this.questionList = questionList; } } public static class ArrayContainer { - public TestInterface[] array; + public final TestInterface[] array; public ArrayContainer(TestInterface[] array) { this.array = array; } } + @SuppressWarnings("OptionalUsedAsFieldOrParameterType") public static class OptionalContainer { - @SuppressWarnings("OptionalUsedAsFieldOrParameterType") - public Optional<TestInterface> optional; + public final Optional<TestInterface> optional; + public final Optional<?> questionOptional; - public OptionalContainer(Optional<TestInterface> optional) { + public OptionalContainer(final Optional<TestInterface> optional, final Optional<?> questionOptional) { this.optional = optional; + this.questionOptional = questionOptional; } } @@ -118,14 +133,28 @@ final MapContainer container = new MapContainer(Map.of( "key1", new TestImpl("value1"), "key2", new TestImpl("value2") - )); + ), Map.of("qKey1", "value1", "qKey2", "value2"), + Map.of("key1", "qValue1", "key2", "qValue2") + ); - final String json = jsonb.toJson(container); + final JsonObject json = toJsonObject(container); + final JsonObject map = json.getJsonObject("map"); + final JsonObject questionKeyMap = json.getJsonObject("questionKeyMap"); + final JsonObject questionValueMap = json.getJsonObject("questionValueMap"); - Assertions.assertTrue(json.contains("\"key1\":\"SERIALIZED:value1\""), - "Expected serialized value1 but got: " + json); - Assertions.assertTrue(json.contains("\"key2\":\"SERIALIZED:value2\""), - "Expected serialized value2 but got: " + json); + Supplier<String> errorMessage = () -> String.format("Expected value not found in %s", map); + Assertions.assertEquals("SERIALIZED:value1", map.getString("key1"), errorMessage); + Assertions.assertEquals("SERIALIZED:value2", map.getString("key2"), errorMessage); + + + errorMessage = () -> String.format("Expected value not found in %s", questionKeyMap); + Assertions.assertEquals("value1", questionKeyMap.getString("qKey1"), errorMessage); + Assertions.assertEquals("value2", questionKeyMap.getString("qKey2"), errorMessage); + + + errorMessage = () -> String.format("Expected value not found in %s", questionValueMap); + Assertions.assertEquals("qValue1", questionValueMap.getString("key1"), errorMessage); + Assertions.assertEquals("qValue2", questionValueMap.getString("key2"), errorMessage); } @Test @@ -133,16 +162,26 @@ final ListContainer container = new ListContainer(List.of( new TestImpl("value1"), new TestImpl("value2") - )); + ), List.of("qValue1", "qValue2")); - final String json = jsonb.toJson(container); + final JsonObject json = toJsonObject(container); + final JsonArray list = json.getJsonArray("list"); + final JsonArray questionList = json.getJsonArray("questionList"); - Assertions.assertEquals("{\"list\":[\"SERIALIZED:value1\",\"SERIALIZED:value2\"]}", json); + Supplier<String> errorMessage = () -> String.format("Expected value not found in %s", list); + Assertions.assertEquals(2, list.size(), () -> String.format("Expected a size of 2 in %s", list)); + Assertions.assertEquals("SERIALIZED:value1", list.getString(0), errorMessage); + Assertions.assertEquals("SERIALIZED:value2", list.getString(1), errorMessage); + + errorMessage = () -> String.format("Expected value not found in %s", questionList); + Assertions.assertEquals(2, questionList.size(), () -> String.format("Expected a size of 2 in %s", questionList)); + Assertions.assertEquals("qValue1", questionList.getString(0), errorMessage); + Assertions.assertEquals("qValue2", questionList.getString(1), errorMessage); } @Test public void testTypeSerializerOnArrayElements() { - final ArrayContainer container = new ArrayContainer(new TestInterface[]{ + final ArrayContainer container = new ArrayContainer(new TestInterface[] { new TestImpl("value1"), new TestImpl("value2") }); @@ -154,10 +193,21 @@ @Test public void testTypeSerializerOnOptionalValue() { - final OptionalContainer container = new OptionalContainer(Optional.of(new TestImpl("value1"))); + final OptionalContainer container = new OptionalContainer(Optional.of(new TestImpl("value1")), Optional.of("value2")); - final String json = jsonb.toJson(container); + final JsonObject json = toJsonObject(container); - Assertions.assertEquals("{\"optional\":\"SERIALIZED:value1\"}", json); + Assertions.assertEquals("SERIALIZED:value1", json.getString("optional")); + Assertions.assertEquals("value2", json.getString("questionOptional")); + } + + private JsonObject toJsonObject(final Object object) throws JsonbException { + final String value = jsonb.toJson(object); + try ( + StringReader reader = new StringReader(value); + JsonReader jsonReader = Json.createReader(reader) + ) { + return jsonReader.readObject(); + } } }