|
1 | 1 | /*
|
2 |
| - * Copyright (c) 2019, 2022 Oracle and/or its affiliates. All rights reserved. |
| 2 | + * Copyright (c) 2019, 2025 Oracle and/or its affiliates. All rights reserved. |
3 | 3 | *
|
4 | 4 | * This program and the accompanying materials are made available under the
|
5 | 5 | * terms of the Eclipse Public License v. 2.0 which is available at
|
|
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