From 1ba0b078387372aa1ea9154eed7175adcd081193 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Wed, 3 Jan 2024 11:03:21 -0800 Subject: [PATCH] Solve NPE part of #296 (#298) --- .../jsr310/ser/LocalDateSerializer.java | 10 +-- .../jsr310/ser/LocalDateTimeSerializer.java | 2 +- .../jsr310/ser/LocalTimeSerializer.java | 3 +- .../jsr310/ser/MonthDaySerializer.java | 3 +- .../jsr310/ser/OffsetTimeSerializer.java | 3 +- .../jsr310/ser/YearMonthSerializer.java | 3 +- .../DeductionTypeSerialization296Test.java | 84 +++++++++++++++++++ release-notes/VERSION-2.x | 5 ++ 8 files changed, 102 insertions(+), 11 deletions(-) create mode 100644 datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/misc/DeductionTypeSerialization296Test.java diff --git a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/ser/LocalDateSerializer.java b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/ser/LocalDateSerializer.java index 14c77040..e799dd10 100644 --- a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/ser/LocalDateSerializer.java +++ b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/ser/LocalDateSerializer.java @@ -83,14 +83,12 @@ public void serializeWithType(LocalDate value, JsonGenerator g, WritableTypeId typeIdDef = typeSer.writeTypePrefix(g, typeSer.typeId(value, serializationShape(provider))); // need to write out to avoid double-writing array markers - switch (typeIdDef.valueShape) { - case START_ARRAY: + JsonToken shape = (typeIdDef == null) ? null : typeIdDef.valueShape; + if (shape == JsonToken.START_ARRAY) { _serializeAsArrayContents(value, g, provider); - break; - case VALUE_NUMBER_INT: + } else if (shape == JsonToken.VALUE_NUMBER_INT) { g.writeNumber(value.toEpochDay()); - break; - default: + } else { g.writeString((_formatter == null) ? value.toString() : value.format(_formatter)); } typeSer.writeTypeSuffix(g, typeIdDef); diff --git a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/ser/LocalDateTimeSerializer.java b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/ser/LocalDateTimeSerializer.java index 4fe5e406..4383a36a 100644 --- a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/ser/LocalDateTimeSerializer.java +++ b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/ser/LocalDateTimeSerializer.java @@ -86,7 +86,7 @@ public void serializeWithType(LocalDateTime value, JsonGenerator g, SerializerPr WritableTypeId typeIdDef = typeSer.writeTypePrefix(g, typeSer.typeId(value, serializationShape(provider))); // need to write out to avoid double-writing array markers - if (typeIdDef.valueShape == JsonToken.START_ARRAY) { + if ((typeIdDef != null) && typeIdDef.valueShape == JsonToken.START_ARRAY) { _serializeAsArrayContents(value, g, provider); } else { DateTimeFormatter dtf = _formatter; diff --git a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/ser/LocalTimeSerializer.java b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/ser/LocalTimeSerializer.java index 68f2080e..e43586d5 100644 --- a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/ser/LocalTimeSerializer.java +++ b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/ser/LocalTimeSerializer.java @@ -94,7 +94,8 @@ public void serializeWithType(LocalTime value, JsonGenerator g, WritableTypeId typeIdDef = typeSer.writeTypePrefix(g, typeSer.typeId(value, serializationShape(provider))); // need to write out to avoid double-writing array markers - if (typeIdDef.valueShape == JsonToken.START_ARRAY) { + if ((typeIdDef != null) + && typeIdDef.valueShape == JsonToken.START_ARRAY) { _serializeAsArrayContents(value, g, provider); } else { DateTimeFormatter dtf = _formatter; diff --git a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/ser/MonthDaySerializer.java b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/ser/MonthDaySerializer.java index 10fc0b0b..46f7aa35 100644 --- a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/ser/MonthDaySerializer.java +++ b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/ser/MonthDaySerializer.java @@ -81,7 +81,8 @@ public void serializeWithType(MonthDay value, JsonGenerator g, WritableTypeId typeIdDef = typeSer.writeTypePrefix(g, typeSer.typeId(value, serializationShape(provider))); // need to write out to avoid double-writing array markers - if (typeIdDef.valueShape == JsonToken.START_ARRAY) { + if ((typeIdDef != null) + && typeIdDef.valueShape == JsonToken.START_ARRAY) { _serializeAsArrayContents(value, g, provider); } else { g.writeString((_formatter == null) ? value.toString() : value.format(_formatter)); diff --git a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/ser/OffsetTimeSerializer.java b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/ser/OffsetTimeSerializer.java index 1c78d462..f1dec8b9 100644 --- a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/ser/OffsetTimeSerializer.java +++ b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/ser/OffsetTimeSerializer.java @@ -79,7 +79,8 @@ public void serializeWithType(OffsetTime value, JsonGenerator g, SerializerProvi WritableTypeId typeIdDef = typeSer.writeTypePrefix(g, typeSer.typeId(value, serializationShape(provider))); // need to write out to avoid double-writing array markers - if (typeIdDef.valueShape == JsonToken.START_ARRAY) { + if ((typeIdDef != null) + && typeIdDef.valueShape == JsonToken.START_ARRAY) { _serializeAsArrayContents(value, g, provider); } else { String str = (_formatter == null) ? value.toString() : value.format(_formatter); diff --git a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/ser/YearMonthSerializer.java b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/ser/YearMonthSerializer.java index bca1adcb..fcafb737 100644 --- a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/ser/YearMonthSerializer.java +++ b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/ser/YearMonthSerializer.java @@ -82,7 +82,8 @@ public void serializeWithType(YearMonth value, JsonGenerator g, WritableTypeId typeIdDef = typeSer.writeTypePrefix(g, typeSer.typeId(value, serializationShape(provider))); // need to write out to avoid double-writing array markers - if (typeIdDef.valueShape == JsonToken.START_ARRAY) { + if ((typeIdDef != null) + && typeIdDef.valueShape == JsonToken.START_ARRAY) { _serializeAsArrayContents(value, g, provider); } else { g.writeString((_formatter == null) ? value.toString() : value.format(_formatter)); diff --git a/datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/misc/DeductionTypeSerialization296Test.java b/datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/misc/DeductionTypeSerialization296Test.java new file mode 100644 index 00000000..08ce9d08 --- /dev/null +++ b/datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/misc/DeductionTypeSerialization296Test.java @@ -0,0 +1,84 @@ +package com.fasterxml.jackson.datatype.jsr310.misc; + +import java.time.*; + +import org.junit.Assert; +import org.junit.Test; + +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.datatype.jsr310.ModuleTestBase; + +// for [modules-java8#296]: problem with `JsonTypeInfo.Id.DEDUCTION` +public class DeductionTypeSerialization296Test extends ModuleTestBase +{ + static class Wrapper { + @JsonTypeInfo(use = JsonTypeInfo.Id.DEDUCTION) + public Object value; + + public Wrapper(Object value) { + this.value = value; + } + } + + private final ObjectMapper MAPPER = mapperBuilder() + .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) + .build(); + + @Test + public void testLocalDate() throws Exception + { + LocalDate date = LocalDate.of(1986, Month.JANUARY, 17); + Assert.assertEquals(a2q("{'value':'1986-01-17'}"), + MAPPER.writeValueAsString(new Wrapper(date))); + } + + @Test + public void testLocalDateTime() throws Exception + { + LocalDateTime datetime = LocalDateTime.of(2013, Month.AUGUST, 21, 9, 22, 0, 57); + Assert.assertEquals(a2q("{'value':'2013-08-21T09:22:00.000000057'}"), + MAPPER.writeValueAsString(new Wrapper(datetime))); + } + + @Test + public void testLocalTime() throws Exception + { + LocalTime time = LocalTime.of(9, 22, 57); + Assert.assertEquals(a2q("{'value':'09:22:57'}"), + MAPPER.writeValueAsString(new Wrapper(time))); + } + + @Test + public void testMonthDate() throws Exception + { + MonthDay date = MonthDay.of(Month.JANUARY, 17); + Assert.assertEquals(a2q("{'value':'--01-17'}"), + MAPPER.writeValueAsString(new Wrapper(date))); + } + + @Test + public void testOffsetTime() throws Exception + { + OffsetTime time = OffsetTime.of(15, 43, 0, 0, ZoneOffset.of("+0300")); + Assert.assertEquals(a2q("{'value':'15:43+03:00'}"), + MAPPER.writeValueAsString(new Wrapper(time))); + } + + @Test + public void testYearMonth() throws Exception + { + YearMonth date = YearMonth.of(1986, Month.JANUARY); + Assert.assertEquals(a2q("{'value':'1986-01'}"), + MAPPER.writeValueAsString(new Wrapper(date))); + } + + @Test + public void testZoneId() throws Exception + { + ZoneId zone = ZoneId.of("America/Denver"); + Assert.assertEquals(a2q("{'value':'America/Denver'}"), + MAPPER.writeValueAsString(new Wrapper(zone))); + } +} diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index 88ecc1fb..f0977b3f 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -8,6 +8,11 @@ Modules: === Releases === ------------------------------------------------------------------------ +2.16.2 (not yet released) + +#296: NPE when serializing a `LocalDate` or `LocalDateTime` using `AsDeductionTypeSerializer` + (reported by @mike-reynolds-savient) + 2.16.1 (24-Dec-2023) #286: Breaking change in `InstantDeserializer API between 2.15 and 2.16