|
13 | 13 | package org.eclipse.yasson.serializers; |
14 | 14 |
|
15 | 15 | import org.junit.jupiter.api.*; |
| 16 | +import static org.hamcrest.CoreMatchers.instanceOf; |
| 17 | +import static org.hamcrest.MatcherAssert.assertThat; |
16 | 18 | import static org.junit.jupiter.api.Assertions.*; |
17 | 19 |
|
18 | 20 | import java.io.StringReader; |
19 | 21 | import java.lang.reflect.ParameterizedType; |
20 | 22 | import java.lang.reflect.Type; |
21 | 23 | import java.math.BigDecimal; |
| 24 | +import java.time.LocalDate; |
| 25 | +import java.time.format.DateTimeFormatter; |
| 26 | +import java.time.format.FormatStyle; |
22 | 27 | import java.util.Comparator; |
23 | 28 | import java.util.HashMap; |
24 | 29 | import java.util.Locale; |
@@ -851,6 +856,26 @@ public Locale deserialize(JsonParser parser, DeserializationContext ctx, Type rt |
851 | 856 | } |
852 | 857 | } |
853 | 858 |
|
| 859 | + public static class LocalDateSerializer implements JsonbSerializer<LocalDate> { |
| 860 | + |
| 861 | + private static final DateTimeFormatter SHORT_FORMAT = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT); |
| 862 | + |
| 863 | + @Override |
| 864 | + public void serialize(LocalDate obj, JsonGenerator generator, SerializationContext ctx) { |
| 865 | + generator.write(SHORT_FORMAT.format(obj)); |
| 866 | + } |
| 867 | + } |
| 868 | + |
| 869 | + public static class LocalDateDeserializer implements JsonbDeserializer<LocalDate> { |
| 870 | + |
| 871 | + private static final DateTimeFormatter SHORT_FORMAT = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT); |
| 872 | + |
| 873 | + @Override |
| 874 | + public LocalDate deserialize(JsonParser parser, DeserializationContext ctx, Type rtType) { |
| 875 | + return LocalDate.parse(parser.getString(), SHORT_FORMAT); |
| 876 | + } |
| 877 | + } |
| 878 | + |
854 | 879 | public static class MapObject<K, V> { |
855 | 880 |
|
856 | 881 | private Map<K, V> values; |
@@ -934,4 +959,53 @@ public void testMapLocaleString() { |
934 | 959 | MapObjectLocaleString resObject = jsonb.fromJson(json, MapObjectLocaleString.class); |
935 | 960 | assertEquals(mapObject, resObject); |
936 | 961 | } |
| 962 | + |
| 963 | + public static class MapObjectLocalDateString extends MapObject<LocalDate, String> {}; |
| 964 | + |
| 965 | + private void verifyMapObjectCustomLocalDateStringSerialization(JsonObject jsonObject, MapObjectLocalDateString mapObject) { |
| 966 | + |
| 967 | + // Expected serialization is: {"values":[{"key":"short-local-date","value":"string"},...]} |
| 968 | + assertEquals(1, jsonObject.size()); |
| 969 | + assertNotNull(jsonObject.get("values")); |
| 970 | + assertEquals(JsonValue.ValueType.ARRAY, jsonObject.get("values").getValueType()); |
| 971 | + JsonArray jsonArray = jsonObject.getJsonArray("values"); |
| 972 | + assertEquals(mapObject.getValues().size(), jsonArray.size()); |
| 973 | + MapObjectLocalDateString resObject = new MapObjectLocalDateString(); |
| 974 | + for (JsonValue jsonValue : jsonArray) { |
| 975 | + assertEquals(JsonValue.ValueType.OBJECT, jsonValue.getValueType()); |
| 976 | + JsonObject entry = jsonValue.asJsonObject(); |
| 977 | + assertEquals(2, entry.size()); |
| 978 | + assertNotNull(entry.get("key")); |
| 979 | + assertEquals(JsonValue.ValueType.STRING, entry.get("key").getValueType()); |
| 980 | + assertNotNull(entry.get("value")); |
| 981 | + assertEquals(JsonValue.ValueType.STRING, entry.get("value").getValueType()); |
| 982 | + resObject.getValues().put(LocalDate.parse(entry.getString("key"), DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT)), entry.getString("value")); |
| 983 | + } |
| 984 | + assertEquals(mapObject, resObject); |
| 985 | + } |
| 986 | + |
| 987 | + /** |
| 988 | + * Test for issue #663... |
| 989 | + * Test a LocalDate/String map as member in a custom class, using a custom LocalDate serializer and deserializer, |
| 990 | + * even though there's a build-in {@link org.eclipse.yasson.internal.serializer.types.TypeSerializers#isSupportedMapKey(Class)} |
| 991 | + */ |
| 992 | + @Test |
| 993 | + public void testMapLocalDateKeyStringValueAsMember() { |
| 994 | + Jsonb jsonb = JsonbBuilder.create(new JsonbConfig() |
| 995 | + .withSerializers(new LocalDateSerializer()) |
| 996 | + .withDeserializers(new LocalDateDeserializer())); |
| 997 | + |
| 998 | + MapObjectLocalDateString mapObject = new MapObjectLocalDateString(); |
| 999 | + mapObject.getValues().put(LocalDate.now(), "today"); |
| 1000 | + mapObject.getValues().put(LocalDate.now().plusDays(1), "tomorrow"); |
| 1001 | + |
| 1002 | + String json = jsonb.toJson(mapObject); |
| 1003 | + |
| 1004 | + JsonObject jsonObject = Json.createReader(new StringReader(json)).read().asJsonObject(); |
| 1005 | + verifyMapObjectCustomLocalDateStringSerialization(jsonObject, mapObject); |
| 1006 | + MapObjectLocalDateString resObject = jsonb.fromJson(json, MapObjectLocalDateString.class); |
| 1007 | + assertEquals(mapObject, resObject); |
| 1008 | + // ensure the keys are of type java.time.LocalDate |
| 1009 | + assertThat(resObject.getValues().keySet().iterator().next(), instanceOf(LocalDate.class)); |
| 1010 | + } |
937 | 1011 | } |
0 commit comments