Fix #651: Support TIME_IN_MILLIS and locale-only @JsonbDateFormat on creator parameters AnnotationIntrospector.getConstructorDateFormatter() always passed the value of @JsonbDateFormat to DateTimeFormatter.ofPattern(), including the TIME_IN_MILLIS and DEFAULT_FORMAT markers, so deserializing a record or a @JsonbCreator parameter annotated with @JsonbDateFormat(TIME_IN_MILLIS), or with only a locale, failed with "Pattern includes reserved character: '#'". Handle these two markers as for properties: they are not patterns, the date converters use the epoch millis or the default formats for them. Signed-off-by: Sharang Gupta <sharang@sharanggupta.dev>
diff --git a/src/main/java/org/eclipse/yasson/internal/AnnotationIntrospector.java b/src/main/java/org/eclipse/yasson/internal/AnnotationIntrospector.java index 2228c51..8edc2af 100644 --- a/src/main/java/org/eclipse/yasson/internal/AnnotationIntrospector.java +++ b/src/main/java/org/eclipse/yasson/internal/AnnotationIntrospector.java
@@ -1,5 +1,6 @@ /* * Copyright (c) 2016, 2026 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026 Contributors to the Eclipse Foundation * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at @@ -594,9 +595,16 @@ */ public JsonbDateFormatter getConstructorDateFormatter(JsonbAnnotatedElement<Parameter> param) { return param.getAnnotation(JsonbDateFormat.class) - .map(annotation -> new JsonbDateFormatter(DateTimeFormatter.ofPattern(annotation.value(), - Locale.forLanguageTag(annotation.locale())), - annotation.value(), annotation.locale())) + .map(annotation -> { + String format = annotation.value(); + String locale = annotation.locale(); + if (JsonbDateFormat.TIME_IN_MILLIS.equals(format) || JsonbDateFormat.DEFAULT_FORMAT.equals(format)) { + //not patterns, handled by the date converters as for properties + return new JsonbDateFormatter(format, locale); + } + return new JsonbDateFormatter(DateTimeFormatter.ofPattern(format, Locale.forLanguageTag(locale)), + format, locale); + }) .orElse(null); }
diff --git a/src/test/java/org/eclipse/yasson/records/RecordTest.java b/src/test/java/org/eclipse/yasson/records/RecordTest.java index edaee35..bf3ad00 100644 --- a/src/test/java/org/eclipse/yasson/records/RecordTest.java +++ b/src/test/java/org/eclipse/yasson/records/RecordTest.java
@@ -24,6 +24,8 @@ import org.eclipse.yasson.internal.properties.Messages; import org.junit.jupiter.api.Test; +import java.time.Instant; +import java.time.LocalDate; import java.util.List; import java.util.Set; @@ -50,6 +52,18 @@ } @Test + public void testRecordWithDateFormats() { + String json = "{\"iso\":\"2024-10-11T13:28:22Z\",\"localeOnly\":\"2024-10-11\",\"millis\":1728574424000}"; + + RecordWithDateFormats deserialized = Jsonbs.defaultJsonb.fromJson(json, RecordWithDateFormats.class); + + assertEquals(Instant.ofEpochMilli(1728574424000L), deserialized.millis()); + assertEquals(LocalDate.of(2024, 10, 11), deserialized.localeOnly()); + assertEquals(Instant.parse("2024-10-11T13:28:22Z"), deserialized.iso()); + assertEquals(json, Jsonbs.defaultJsonb.toJson(deserialized)); + } + + @Test public void testRecordProcessingWithoutJsonbProperties() { CarWithoutAnnotations car = new CarWithoutAnnotations("skoda", "green"); String expected = "{\"color\":\"green\",\"type\":\"skoda\"}";
diff --git a/src/test/java/org/eclipse/yasson/records/RecordWithDateFormats.java b/src/test/java/org/eclipse/yasson/records/RecordWithDateFormats.java new file mode 100644 index 0000000..a247f13 --- /dev/null +++ b/src/test/java/org/eclipse/yasson/records/RecordWithDateFormats.java
@@ -0,0 +1,23 @@ +/* + * Copyright (c) 2026 Contributors to the Eclipse Foundation + * + * 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.records; + +import java.time.Instant; +import java.time.LocalDate; + +import jakarta.json.bind.annotation.JsonbDateFormat; + +public record RecordWithDateFormats(@JsonbDateFormat(JsonbDateFormat.TIME_IN_MILLIS) Instant millis, + @JsonbDateFormat(locale = "de") LocalDate localeOnly, + Instant iso) { +}