| 
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