Skip to content

Commit de54f0c

Browse files
authored
fix #333 @JsonFormat with pattern should override SerializationFeature.WRITE_DATES_WITH_ZONE_ID (#334)
1 parent 10e7f64 commit de54f0c

File tree

5 files changed

+67
-7
lines changed

5 files changed

+67
-7
lines changed

datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/ser/InstantSerializerBase.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,12 @@ public abstract class InstantSerializerBase<T extends Temporal>
5757

5858
protected InstantSerializerBase(Class<T> supportedType, ToLongFunction<T> getEpochMillis,
5959
ToLongFunction<T> getEpochSeconds, ToIntFunction<T> getNanoseconds,
60-
DateTimeFormatter formatter)
60+
DateTimeFormatter defaultFormat)
6161
{
6262
// Bit complicated, just because we actually want to "hide" default formatter,
6363
// so that it won't accidentally force use of textual presentation
6464
super(supportedType, null);
65-
defaultFormat = formatter;
65+
this.defaultFormat = defaultFormat;
6666
this.getEpochMillis = getEpochMillis;
6767
this.getEpochSeconds = getEpochSeconds;
6868
this.getNanoseconds = getNanoseconds;
@@ -147,7 +147,7 @@ protected JsonToken serializationShape(SerializerProvider provider) {
147147
// @since 2.12
148148
protected String formatValue(T value, SerializerProvider provider)
149149
{
150-
DateTimeFormatter formatter = (_formatter != null) ? _formatter : defaultFormat;
150+
DateTimeFormatter formatter = (_formatter == null) ? defaultFormat :_formatter;
151151
if (formatter != null) {
152152
if (formatter.getZone() == null) { // timezone set if annotated on property
153153
// If the user specified to use the context TimeZone explicitly, and the formatter provided doesn't contain a TZ

datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/ser/JSR310FormattedSerializerBase.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ abstract class JSR310FormattedSerializerBase<T>
5959
protected final Boolean _useNanoseconds;
6060

6161
/**
62-
* Specific format to use, if not default format: non null value
62+
* Specific format to use, if not default format: non-null value
6363
* also indicates that serialization is to be done as JSON String,
6464
* not numeric timestamp, unless {@code #_useTimestamp} is true.
6565
*/

datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/ser/ZonedDateTimeSerializer.java

+19-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,11 @@ public void serialize(ZonedDateTime value, JsonGenerator g, SerializerProvider p
8383
throws IOException
8484
{
8585
if (!useTimestamp(provider)) {
86-
if (shouldWriteWithZoneId(provider)) {
86+
// [modules-java8#333]: `@JsonFormat` with pattern should override
87+
// `SerializationFeature.WRITE_DATES_WITH_ZONE_ID`
88+
if ((_formatter != null) && (_shape == JsonFormat.Shape.STRING)) {
89+
; // use default handling
90+
} else if (shouldWriteWithZoneId(provider)) {
8791
// write with zone
8892
g.writeString(DateTimeFormatter.ISO_ZONED_DATE_TIME.format(value));
8993
return;
@@ -92,6 +96,20 @@ public void serialize(ZonedDateTime value, JsonGenerator g, SerializerProvider p
9296
super.serialize(value, g, provider);
9397
}
9498

99+
@Override
100+
protected String formatValue(ZonedDateTime value, SerializerProvider provider) {
101+
String formatted = super.formatValue(value, provider);
102+
// [modules-java8#333]: `@JsonFormat` with pattern should override
103+
// `SerializationFeature.WRITE_DATES_WITH_ZONE_ID`
104+
if (_formatter != null && _shape == JsonFormat.Shape.STRING) {
105+
// Why not `if (shouldWriteWithZoneId(provider))` ?
106+
if (Boolean.TRUE.equals(_writeZoneId)) {
107+
formatted += "[" + value.getZone().getId() + "]";
108+
}
109+
}
110+
return formatted;
111+
}
112+
95113
/**
96114
* @since 2.8
97115
*/

datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/ser/WriteZoneIdTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public class WriteZoneIdTest extends ModuleTestBase
2121
{
2222
static class DummyClassWithDate {
2323
@JsonFormat(shape = JsonFormat.Shape.STRING,
24-
pattern = "dd-MM-yyyy hh:mm:ss Z",
24+
pattern = "dd-MM-yyyy'T'hh:mm:ss Z",
2525
with = JsonFormat.Feature.WRITE_DATES_WITH_ZONE_ID)
2626
public ZonedDateTime date;
2727

@@ -73,7 +73,7 @@ public void testJacksonAnnotatedPOJOWithDateWithTimezoneToJson() throws Exceptio
7373
// 30-Jun-2016, tatu: Exact time seems to vary a bit based on DST, so let's actually
7474
// just verify appending of timezone id itself:
7575
String json = MAPPER.writeValueAsString(input);
76-
if (!json.contains("\"1970-01-01T")) {
76+
if (!json.contains("\"01-01-1970T")) {
7777
Assert.fail("Should contain time prefix, did not: "+json);
7878
}
7979
String match = String.format("[%s]", ZONE_ID_STR);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.fasterxml.jackson.datatype.jsr310.ser;
2+
3+
import java.time.ZonedDateTime;
4+
5+
import org.junit.Test;
6+
7+
import com.fasterxml.jackson.annotation.JsonFormat;
8+
import com.fasterxml.jackson.databind.ObjectMapper;
9+
import com.fasterxml.jackson.databind.SerializationFeature;
10+
import com.fasterxml.jackson.datatype.jsr310.ModuleTestBase;
11+
12+
import static org.junit.Assert.assertEquals;
13+
14+
// [module-java8#333]: ZonedDateTime serialization with @JsonFormat pattern never uses
15+
// while WRITE_DATES_WITH_ZONE_ID enabled #333
16+
public class ZonedDateTimeSerWithJsonFormat333Test
17+
extends ModuleTestBase
18+
{
19+
public static class ContainerWithPattern333 {
20+
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss z")
21+
public ZonedDateTime value;
22+
}
23+
24+
public static class ContainerWithoutPattern333 {
25+
@JsonFormat(shape = JsonFormat.Shape.STRING)
26+
public ZonedDateTime value;
27+
}
28+
29+
private final ObjectMapper MAPPER = mapperBuilder().enable(SerializationFeature.WRITE_DATES_WITH_ZONE_ID).build();
30+
31+
@Test
32+
public void testJsonFormatOverridesSerialization() throws Exception
33+
{
34+
// ISO-8601 string for ZonedDateTime
35+
ZonedDateTime zonedDateTime = ZonedDateTime.parse("2024-11-15T18:27:06.921054+01:00[Europe/Berlin]");
36+
ContainerWithPattern333 input = new ContainerWithPattern333();
37+
input.value = zonedDateTime;
38+
39+
assertEquals(a2q("{'value':'2024-11-15 18:27:06 CET'}"),
40+
MAPPER.writeValueAsString(input));
41+
}
42+
}

0 commit comments

Comments
 (0)