From 03d024cdc9577ad999d97a5e2f51495339e5b838 Mon Sep 17 00:00:00 2001 From: Tom Gottfried Date: Mon, 10 Nov 2025 17:20:01 +0100 Subject: [PATCH 1/2] Add some tests of timestamp serialization --- .../serializers/TimeSerializersTest.java | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 src/test/java/org/eclipse/yasson/serializers/TimeSerializersTest.java diff --git a/src/test/java/org/eclipse/yasson/serializers/TimeSerializersTest.java b/src/test/java/org/eclipse/yasson/serializers/TimeSerializersTest.java new file mode 100644 index 000000000..9d7275aed --- /dev/null +++ b/src/test/java/org/eclipse/yasson/serializers/TimeSerializersTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2025 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, + * or the Eclipse Distribution License v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +package org.eclipse.yasson.serializers; + +import static org.eclipse.yasson.Jsonbs.defaultJsonb; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.sql.Timestamp; +import java.util.Date; + +import org.junit.jupiter.api.Test; + +import jakarta.json.bind.Jsonb; +import jakarta.json.bind.JsonbBuilder; +import jakarta.json.bind.JsonbConfig; + +public class TimeSerializersTest { + + private static final String EPOCH_DEFAULT = "\"1970-01-01T00:00:00Z[UTC]\""; + private static final String EPOCH_CUSTOM = "\"1970-01-01T00:00:00.000Z\""; + + private static final Jsonb JSONB_CUSTOM = JsonbBuilder.create( + new JsonbConfig().withDateFormat( + "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'SSSXXX", null)); + + @Test + public void serializeDateDefault() { + Date date = new Date(0l); + assertEquals(EPOCH_DEFAULT, defaultJsonb.toJson(date)); + } + + @Test + public void serializeSqlTimestampDefault() { + Timestamp ts = new Timestamp(0l); + assertEquals(EPOCH_DEFAULT, defaultJsonb.toJson(ts)); + } + + @Test + public void serializeDateCustom() { + Date date = new Date(0l); + assertEquals(EPOCH_CUSTOM, JSONB_CUSTOM.toJson(date)); + } + + @Test // TODO: Fails with ClassCastException + public void serializeSqlTimestampCustom() { + Timestamp ts = new Timestamp(0l); + assertEquals(EPOCH_CUSTOM, JSONB_CUSTOM.toJson(ts)); + } +} From 09314705d4fcb204998bc8c7b5e9699e69ec2a85 Mon Sep 17 00:00:00 2001 From: Tom Gottfried Date: Mon, 10 Nov 2025 17:17:49 +0100 Subject: [PATCH 2/2] Fix serializing java.sql.Timestamp SqlTimestampSerializer missed to override toTemporalAccessor, leading to ClassCastExceptions in the default implementation in AbstractDateSerializer. Since it does all formatting after calling toInstant on the value, we can safely use the same code path as is used for java.util.Date (despite what is said about the inheritance relationship between Date and Timestamp in their API documentation). Closes #687. --- .../types/SqlTimestampSerializer.java | 43 ------------------- .../serializer/types/TypeSerializers.java | 2 +- .../serializers/TimeSerializersTest.java | 2 +- 3 files changed, 2 insertions(+), 45 deletions(-) delete mode 100644 src/main/java/org/eclipse/yasson/internal/serializer/types/SqlTimestampSerializer.java diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/SqlTimestampSerializer.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/SqlTimestampSerializer.java deleted file mode 100644 index 166047342..000000000 --- a/src/main/java/org/eclipse/yasson/internal/serializer/types/SqlTimestampSerializer.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2019, 2022 Oracle and/or its affiliates. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v. 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0, - * or the Eclipse Distribution License v. 1.0 which is available at - * http://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause - */ - -package org.eclipse.yasson.internal.serializer.types; - -import java.sql.Timestamp; -import java.time.Instant; -import java.time.format.DateTimeFormatter; -import java.util.Locale; - -/** - * Serializer of the {@link Timestamp} type. - */ -class SqlTimestampSerializer extends AbstractDateSerializer { - - /** - * Default Yasson {@link DateTimeFormatter}. - */ - private static final DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormatter.ISO_DATE_TIME.withZone(UTC); - - SqlTimestampSerializer(TypeSerializerBuilder serializerBuilder) { - super(serializerBuilder); - } - - @Override - protected Instant toInstant(Timestamp value) { - return value.toInstant(); - } - - @Override - protected String formatDefault(Timestamp value, Locale locale) { - return DEFAULT_FORMATTER.withLocale(locale).format(toInstant(value)); - } -} diff --git a/src/main/java/org/eclipse/yasson/internal/serializer/types/TypeSerializers.java b/src/main/java/org/eclipse/yasson/internal/serializer/types/TypeSerializers.java index 3d52abee8..7c782b812 100644 --- a/src/main/java/org/eclipse/yasson/internal/serializer/types/TypeSerializers.java +++ b/src/main/java/org/eclipse/yasson/internal/serializer/types/TypeSerializers.java @@ -121,7 +121,7 @@ public class TypeSerializers { if (isClassAvailable("java.sql.Date")) { cache.put(Date.class, SqlDateSerializer::new); cache.put(java.sql.Date.class, SqlDateSerializer::new); - cache.put(java.sql.Timestamp.class, SqlTimestampSerializer::new); + cache.put(java.sql.Timestamp.class, SqlDateSerializer::new); } SERIALIZERS = Map.copyOf(cache); diff --git a/src/test/java/org/eclipse/yasson/serializers/TimeSerializersTest.java b/src/test/java/org/eclipse/yasson/serializers/TimeSerializersTest.java index 9d7275aed..8fd545de6 100644 --- a/src/test/java/org/eclipse/yasson/serializers/TimeSerializersTest.java +++ b/src/test/java/org/eclipse/yasson/serializers/TimeSerializersTest.java @@ -51,7 +51,7 @@ public void serializeDateCustom() { assertEquals(EPOCH_CUSTOM, JSONB_CUSTOM.toJson(date)); } - @Test // TODO: Fails with ClassCastException + @Test public void serializeSqlTimestampCustom() { Timestamp ts = new Timestamp(0l); assertEquals(EPOCH_CUSTOM, JSONB_CUSTOM.toJson(ts));