From 22acd5953ba95face689346420906d5762bb37e2 Mon Sep 17 00:00:00 2001 From: samwill <19scwilliamson92@gmail.com> Date: Fri, 1 Nov 2019 22:06:35 -0500 Subject: [PATCH] Fixes #148: Deserializes Dates, Times, and DateTimes using DateTimeFormatter with ResolverStyle.STRICT when JsonFormat lenient = false (#151) --- .../deser/JSR310DateTimeDeserializerBase.java | 6 ++++ .../jsr310/deser/LocalDateDeserTest.java | 25 +++++++++++++ .../jsr310/deser/LocalDateTimeDeserTest.java | 36 +++++++++++++++++++ .../jsr310/deser/LocalTimeDeserTest.java | 28 ++++++++++++++- 4 files changed, 94 insertions(+), 1 deletion(-) diff --git a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/JSR310DateTimeDeserializerBase.java b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/JSR310DateTimeDeserializerBase.java index d4087f82..07837b94 100644 --- a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/JSR310DateTimeDeserializerBase.java +++ b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/JSR310DateTimeDeserializerBase.java @@ -3,6 +3,7 @@ import java.io.IOException; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; +import java.time.format.ResolverStyle; import java.util.Locale; import com.fasterxml.jackson.annotation.JsonFormat; @@ -137,6 +138,11 @@ public JsonDeserializer createContextual(DeserializationContext ctxt, } else { df = builder.toFormatter(locale); } + + if (format.hasLenient() && !format.isLenient()) { + df = df.withResolverStyle(ResolverStyle.STRICT); + } + //Issue #69: For instant serializers/deserializers we need to configure the formatter with //a time zone picked up from JsonFormat annotation, otherwise serialization might not work if (format.hasTimeZone()) { diff --git a/datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateDeserTest.java b/datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateDeserTest.java index 0637ffa8..f1b25232 100644 --- a/datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateDeserTest.java +++ b/datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateDeserTest.java @@ -15,6 +15,8 @@ import java.time.temporal.Temporal; import java.util.Map; +import com.fasterxml.jackson.annotation.OptBoolean; +import com.fasterxml.jackson.databind.exc.InvalidFormatException; import org.junit.Test; import com.fasterxml.jackson.annotation.JsonFormat; @@ -54,6 +56,15 @@ public ShapeWrapper() { } public ShapeWrapper(LocalDate v) { date = v; } } + final static class StrictWrapper { + @JsonFormat(pattern="yyyy-MM-dd", + lenient = OptBoolean.FALSE) + public LocalDate value; + + public StrictWrapper() { } + public StrictWrapper(LocalDate v) { value = v; } + } + /* /********************************************************** /* Deserialization from Int array representation @@ -295,6 +306,20 @@ public void testCustomFormat() throws Exception assertEquals(28, date.getDayOfMonth()); } + + /* + /********************************************************** + /* Strict Custom format + /********************************************************** + */ + + // for [modules-java8#148] + @Test(expected = InvalidFormatException.class) + public void testStrictCustomFormat() throws Exception + { + StrictWrapper w = MAPPER.readValue("{\"value\":\"2019-11-31\"}", StrictWrapper.class); + } + /* /********************************************************************** /* Case-insensitive tests diff --git a/datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateTimeDeserTest.java b/datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateTimeDeserTest.java index ea8b7b5d..698cf8d1 100644 --- a/datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateTimeDeserTest.java +++ b/datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateTimeDeserTest.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat.Feature; import com.fasterxml.jackson.annotation.JsonFormat.Value; +import com.fasterxml.jackson.annotation.OptBoolean; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonToken; @@ -52,6 +53,15 @@ public class LocalDateTimeDeserTest private final static ObjectReader READER = MAPPER.readerFor(LocalDateTime.class); private final TypeReference> MAP_TYPE_REF = new TypeReference>() { }; + final static class StrictWrapper { + @JsonFormat(pattern="yyyy-MM-dd HH:mm", + lenient = OptBoolean.FALSE) + public LocalDateTime value; + + public StrictWrapper() { } + public StrictWrapper(LocalDateTime v) { value = v; } + } + /* /********************************************************** /* Tests for deserializing from int array @@ -458,6 +468,32 @@ public void testDeserializationCaseInsensitiveDisabled_InvalidDate() throws Thro } } + /* + /********************************************************************** + /* Strict JsonFormat tests + /********************************************************************** + */ + + // [modules-java8#148]: handle strict deserializaiton for date/time + @Test(expected = InvalidFormatException.class) + public void testStrictCustomFormatInvalidDate() throws Exception + { + StrictWrapper w = MAPPER.readValue("{\"value\":\"2019-11-31 15:45\"}", StrictWrapper.class); + } + + @Test(expected = InvalidFormatException.class) + public void testStrictCustomFormatInvalidTime() throws Exception + { + StrictWrapper w = MAPPER.readValue("{\"value\":\"2019-11-30 25:45\"}", StrictWrapper.class); + } + + @Test(expected = InvalidFormatException.class) + public void testStrictCustomFormatInvalidDateAndTime() throws Exception + { + StrictWrapper w = MAPPER.readValue("{\"value\":\"2019-11-31 25:45\"}", StrictWrapper.class); + } + + private void expectSuccess(ObjectReader reader, Object exp, String json) throws IOException { final LocalDateTime value = reader.readValue(aposToQuotes(json)); assertNotNull("The value should not be null.", value); diff --git a/datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalTimeDeserTest.java b/datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalTimeDeserTest.java index 26c6b6a7..1c280399 100644 --- a/datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalTimeDeserTest.java +++ b/datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalTimeDeserTest.java @@ -31,11 +31,13 @@ import static org.junit.Assert.fail; import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.OptBoolean; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectReader; +import com.fasterxml.jackson.databind.exc.InvalidFormatException; import com.fasterxml.jackson.databind.exc.MismatchedInputException; import com.fasterxml.jackson.datatype.jsr310.MockObjectConfiguration; import com.fasterxml.jackson.datatype.jsr310.ModuleTestBase; @@ -44,9 +46,19 @@ public class LocalTimeDeserTest extends ModuleTestBase { - private ObjectReader reader = newMapper().readerFor(LocalTime.class); + private final static ObjectMapper MAPPER = newMapper(); + private ObjectReader reader = MAPPER.readerFor(LocalTime.class); private final TypeReference> MAP_TYPE_REF = new TypeReference>() { }; + final static class StrictWrapper { + @JsonFormat(pattern="HH:mm", + lenient = OptBoolean.FALSE) + public LocalDateTime value; + + public StrictWrapper() { } + public StrictWrapper(LocalDateTime v) { value = v; } + } + @Test public void testDeserializationAsTimestamp01() throws Exception { @@ -258,6 +270,20 @@ public void testStrictDeserializeFromEmptyString() throws Exception { objectReader.readValue(valueFromEmptyStr); } + /* + /********************************************************************** + /* Strict JsonFormat tests + /********************************************************************** + */ + + // [modules-java8#148]: handle strict deserializaiton for date/time + + @Test(expected = InvalidFormatException.class) + public void testStrictCustomFormatInvalidTime() throws Exception + { + StrictWrapper w = MAPPER.readValue("{\"value\":\"25:45\"}", StrictWrapper.class); + } + private void expectFailure(String aposJson) throws Throwable { try { reader.readValue(aposToQuotes(aposJson));