Skip to content

Commit 1aae1df

Browse files
committed
Merge branch '2.11'
2 parents 2d48175 + 1f32a9f commit 1aae1df

12 files changed

+149
-5
lines changed

datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/InstantDeserializer.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,10 @@ protected InstantDeserializer<T> withDateFormat(DateTimeFormatter dtf) {
160160
protected InstantDeserializer<T> withLeniency(Boolean leniency) {
161161
return this;
162162
}
163-
163+
164+
@Override
165+
protected InstantDeserializer<T> withShape(JsonFormat.Shape shape) { return this; }
166+
164167
@SuppressWarnings("unchecked")
165168
@Override
166169
public T deserialize(JsonParser parser, DeserializationContext context) throws IOException

datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/JSR310DateTimeDeserializerBase.java

+41
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import com.fasterxml.jackson.annotation.JsonFormat;
99
import com.fasterxml.jackson.annotation.JsonFormat.Feature;
10+
import com.fasterxml.jackson.annotation.JsonFormat.Shape;
1011
import com.fasterxml.jackson.core.JsonParser;
1112
import com.fasterxml.jackson.core.JsonToken;
1213
import com.fasterxml.jackson.databind.BeanProperty;
@@ -34,29 +35,63 @@ public abstract class JSR310DateTimeDeserializerBase<T>
3435
*/
3536
protected final boolean _isLenient;
3637

38+
/**
39+
* Setting that indicates the {@Link JsonFormat.Shape} specified for this deserializer
40+
* as a {@link JsonFormat.Shape} annotation on property or class, or due to per-type
41+
* "config override", or from global settings:
42+
* If Shape is NUMBER_INT, the input value is considered to be epoch days. If not a
43+
* NUMBER_INT, and the deserializer was not specified with the leniency setting of true,
44+
* then an exception will be thrown.
45+
* @see [jackson-modules-java8#58] for more info
46+
*
47+
* @since 2.11
48+
*/
49+
protected final Shape _shape;
50+
3751
protected JSR310DateTimeDeserializerBase(Class<T> supportedType, DateTimeFormatter f) {
3852
super(supportedType);
3953
_formatter = f;
4054
_isLenient = true;
55+
_shape = null;
4156
}
4257

4358
protected JSR310DateTimeDeserializerBase(JSR310DateTimeDeserializerBase<T> base,
4459
DateTimeFormatter f) {
4560
super(base);
4661
_formatter = f;
4762
_isLenient = base._isLenient;
63+
_shape = base._shape;
4864
}
4965

5066
protected JSR310DateTimeDeserializerBase(JSR310DateTimeDeserializerBase<T> base,
5167
Boolean leniency) {
5268
super(base);
5369
_formatter = base._formatter;
5470
_isLenient = !Boolean.FALSE.equals(leniency);
71+
_shape = base._shape;
72+
}
73+
74+
/**
75+
* @since 2.11
76+
*/
77+
protected JSR310DateTimeDeserializerBase(JSR310DateTimeDeserializerBase<T> base,
78+
Shape shape) {
79+
super(base);
80+
_formatter = base._formatter;
81+
_shape = shape;
82+
_isLenient = base._isLenient;
5583
}
5684

85+
5786
protected abstract JSR310DateTimeDeserializerBase<T> withDateFormat(DateTimeFormatter dtf);
5887
protected abstract JSR310DateTimeDeserializerBase<T> withLeniency(Boolean leniency);
5988

89+
/**
90+
* @since 2.11
91+
*/
92+
protected abstract JSR310DateTimeDeserializerBase<T> withShape(Shape shape);
93+
94+
6095
@Override
6196
public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
6297
BeanProperty property) throws JsonMappingException
@@ -92,6 +127,12 @@ public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
92127
deser = deser.withLeniency(leniency);
93128
}
94129
}
130+
//Issue #58: For LocalDate deserializers we need to configure the formatter with
131+
//a shape picked up from JsonFormat annotation, to decide if the value is EpochSeconds
132+
JsonFormat.Shape shape = format.getShape();
133+
if (shape != null && shape != _shape) {
134+
deser = deser.withShape(shape);
135+
}
95136
// any use for TimeZone?
96137
}
97138
return deser;

datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateDeserializer.java

+15-3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.time.ZoneOffset;
2525
import java.time.format.DateTimeFormatter;
2626

27+
import com.fasterxml.jackson.annotation.JsonFormat;
2728
import com.fasterxml.jackson.core.*;
2829
import com.fasterxml.jackson.databind.DeserializationContext;
2930
import com.fasterxml.jackson.databind.DeserializationFeature;
@@ -61,6 +62,13 @@ protected LocalDateDeserializer(LocalDateDeserializer base, Boolean leniency) {
6162
super(base, leniency);
6263
}
6364

65+
/**
66+
* Since 2.11
67+
*/
68+
protected LocalDateDeserializer(LocalDateDeserializer base, JsonFormat.Shape shape) {
69+
super(base, shape);
70+
}
71+
6472
@Override
6573
protected LocalDateDeserializer withDateFormat(DateTimeFormatter dtf) {
6674
return new LocalDateDeserializer(this, dtf);
@@ -71,6 +79,9 @@ protected LocalDateDeserializer withLeniency(Boolean leniency) {
7179
return new LocalDateDeserializer(this, leniency);
7280
}
7381

82+
@Override
83+
protected LocalDateDeserializer withShape(JsonFormat.Shape shape) { return new LocalDateDeserializer(this, shape); }
84+
7485
@Override
7586
public LocalDate deserialize(JsonParser parser, DeserializationContext context) throws IOException
7687
{
@@ -134,10 +145,11 @@ public LocalDate deserialize(JsonParser parser, DeserializationContext context)
134145
}
135146
// 06-Jan-2018, tatu: Is this actually safe? Do users expect such coercion?
136147
if (parser.hasToken(JsonToken.VALUE_NUMBER_INT)) {
137-
if (!isLenient()) {
138-
return _failForNotLenient(parser, context, JsonToken.VALUE_STRING);
148+
// issue 58 - also check for NUMBER_INT, which needs to be specified when serializing.
149+
if (_shape == JsonFormat.Shape.NUMBER_INT || isLenient()) {
150+
return LocalDate.ofEpochDay(parser.getLongValue());
139151
}
140-
return LocalDate.ofEpochDay(parser.getLongValue());
152+
return _failForNotLenient(parser, context, JsonToken.VALUE_STRING);
141153
}
142154
return _handleUnexpectedToken(context, parser, "Expected array or string.");
143155
}

datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateTimeDeserializer.java

+4
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.time.ZoneOffset;
2424
import java.time.format.DateTimeFormatter;
2525

26+
import com.fasterxml.jackson.annotation.JsonFormat;
2627
import com.fasterxml.jackson.core.JsonParser;
2728
import com.fasterxml.jackson.core.JsonToken;
2829
import com.fasterxml.jackson.core.JsonTokenId;
@@ -66,6 +67,9 @@ protected LocalDateTimeDeserializer withLeniency(Boolean leniency) {
6667
return new LocalDateTimeDeserializer(this, leniency);
6768
}
6869

70+
@Override
71+
protected LocalDateTimeDeserializer withShape(JsonFormat.Shape shape) { return this; }
72+
6973
@Override
7074
public LocalDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException
7175
{

datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalTimeDeserializer.java

+4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.time.LocalTime;
2222
import java.time.format.DateTimeFormatter;
2323

24+
import com.fasterxml.jackson.annotation.JsonFormat;
2425
import com.fasterxml.jackson.core.JsonParser;
2526
import com.fasterxml.jackson.core.JsonToken;
2627
import com.fasterxml.jackson.databind.DeserializationContext;
@@ -56,6 +57,9 @@ protected LocalTimeDeserializer withLeniency(Boolean leniency) {
5657
return this;
5758
}
5859

60+
@Override
61+
protected LocalTimeDeserializer withShape(JsonFormat.Shape shape) { return this; }
62+
5963
@Override
6064
public LocalTime deserialize(JsonParser parser, DeserializationContext context) throws IOException
6165
{

datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/MonthDayDeserializer.java

+4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.time.MonthDay;
66
import java.time.format.DateTimeFormatter;
77

8+
import com.fasterxml.jackson.annotation.JsonFormat;
89
import com.fasterxml.jackson.core.JsonParser;
910
import com.fasterxml.jackson.core.JsonToken;
1011
import com.fasterxml.jackson.databind.DeserializationContext;
@@ -32,6 +33,9 @@ protected MonthDayDeserializer withLeniency(Boolean leniency) {
3233
return this;
3334
}
3435

36+
@Override
37+
protected MonthDayDeserializer withShape(JsonFormat.Shape shape) { return this; }
38+
3539
@Override
3640
public MonthDay deserialize(JsonParser parser, DeserializationContext context) throws IOException
3741
{

datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/OffsetTimeDeserializer.java

+4
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import java.time.ZoneOffset;
2323
import java.time.format.DateTimeFormatter;
2424

25+
import com.fasterxml.jackson.annotation.JsonFormat;
2526
import com.fasterxml.jackson.core.*;
2627
import com.fasterxml.jackson.databind.*;
2728

@@ -53,6 +54,9 @@ protected OffsetTimeDeserializer withLeniency(Boolean leniency) {
5354
return this;
5455
}
5556

57+
@Override
58+
protected OffsetTimeDeserializer withShape(JsonFormat.Shape shape) { return this; }
59+
5660
@Override
5761
public OffsetTime deserialize(JsonParser parser, DeserializationContext context) throws IOException
5862
{

datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/YearDeserializer.java

+4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.fasterxml.jackson.datatype.jsr310.deser;
1818

19+
import com.fasterxml.jackson.annotation.JsonFormat;
1920
import com.fasterxml.jackson.core.JsonParser;
2021
import com.fasterxml.jackson.core.JsonToken;
2122
import com.fasterxml.jackson.databind.DeserializationContext;
@@ -54,6 +55,9 @@ protected YearDeserializer withLeniency(Boolean leniency) {
5455
return this;
5556
}
5657

58+
@Override
59+
protected YearDeserializer withShape(JsonFormat.Shape shape) { return this; }
60+
5761
@Override
5862
public Year deserialize(JsonParser parser, DeserializationContext context) throws IOException
5963
{

datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/YearMonthDeserializer.java

+4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.time.YearMonth;
2222
import java.time.format.DateTimeFormatter;
2323

24+
import com.fasterxml.jackson.annotation.JsonFormat;
2425
import com.fasterxml.jackson.core.JsonParser;
2526
import com.fasterxml.jackson.databind.DeserializationContext;
2627
import com.fasterxml.jackson.databind.DeserializationFeature;
@@ -57,6 +58,9 @@ protected YearMonthDeserializer withLeniency(Boolean leniency) {
5758
return this;
5859
}
5960

61+
@Override
62+
protected YearMonthDeserializer withShape(JsonFormat.Shape shape) { return this; }
63+
6064
@Override
6165
public YearMonth deserialize(JsonParser parser, DeserializationContext context) throws IOException
6266
{

datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateDeserTest.java

+56-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,15 @@ final static class Wrapper {
4444
public Wrapper() { }
4545
public Wrapper(LocalDate v) { value = v; }
4646
}
47-
47+
48+
final static class ShapeWrapper {
49+
@JsonFormat(shape=JsonFormat.Shape.NUMBER_INT)
50+
public LocalDate date;
51+
52+
public ShapeWrapper() { }
53+
public ShapeWrapper(LocalDate v) { date = v; }
54+
}
55+
4856
/*
4957
/**********************************************************
5058
/* Deserialization from Int array representation
@@ -354,6 +362,53 @@ public void testDeserializationCaseInsensitiveDisabled_InvalidDate() throws Thro
354362
}
355363
}
356364

365+
/*
366+
/**********************************************************************
367+
/*
368+
* Tests for issue 58 - NUMBER_INT should be specified when deserializing
369+
* LocalDate as EpochDays
370+
*/
371+
/**********************************************************************
372+
*/
373+
@Test
374+
public void testLenientDeserializeFromNumberInt() throws Exception {
375+
ObjectMapper mapper = newMapper();
376+
mapper.configOverride(LocalDate.class)
377+
.setFormat(JsonFormat.Value.forShape(JsonFormat.Shape.NUMBER_INT));
378+
379+
assertEquals("The value is not correct.", LocalDate.of(1970, Month.MAY, 04),
380+
mapper.readValue("123", LocalDate.class));
381+
}
382+
383+
@Test
384+
public void testStrictDeserializeFromNumberInt() throws Exception
385+
{
386+
ObjectMapper mapper = newMapper();
387+
mapper.configOverride(LocalDate.class)
388+
.setFormat(JsonFormat.Value.forLeniency(false));
389+
390+
ShapeWrapper w = mapper.readValue("{\"date\":123}", ShapeWrapper.class);
391+
LocalDate localDate = w.date;
392+
393+
assertEquals("The value is not correct.", LocalDate.of(1970, Month.MAY, 04),
394+
localDate);
395+
}
396+
397+
@Test(expected = MismatchedInputException.class)
398+
public void testStrictDeserializeFromString() throws Exception
399+
{
400+
ObjectMapper mapper = newMapper();
401+
mapper.configOverride(LocalDate.class)
402+
.setFormat(JsonFormat.Value.forLeniency(false));
403+
404+
mapper.readValue("{\"value\":123}", Wrapper.class);
405+
}
406+
407+
/*
408+
/**********************************************************************
409+
/* Helper methods
410+
/**********************************************************************
411+
*/
357412
private void expectFailure(ObjectReader reader, String json) throws Throwable {
358413
try {
359414
reader.readValue(aposToQuotes(json));

release-notes/CREDITS-2.x

+6
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ Michael O'Keeffe (kupci@github)
6767
* Contributed fix for #51: `YearKeyDeserializer` doesn't work with non-padded
6868
year values
6969
(2.10.0)
70+
* Contributed fix for #58: Should not parse `LocalDate`s from number (timestamp),
71+
(2.11.0)
7072
* Contributed fix for #69: `ZonedDateTime` for times before the epoch do not
7173
serialize correctly
7274
(2.10.0)
@@ -85,3 +87,7 @@ Vetle Leinonen-Roeim (vetler@github)
8587
(2.10.1)
8688
* Contributed fix for #128: Timestamp keys from `ZonedDateTime`
8789
(2.11.0)
90+
91+
Bill O'Neil (billoneil@github)
92+
* Reported #58: Should not parse `LocalDate`s from number (timestamp),
93+
(2.11.0)

release-notes/VERSION-2.x

+3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ Modules:
1010

1111
2.11.0 (not yet released)
1212

13+
#58: Should not parse `LocalDate`s from number (timestamp), or at least
14+
should have an option preventing
15+
(reported by Bill O'N, fixed by Mike [kupci@github])
1316
#128: Timestamp keys from `ZonedDateTime`
1417
(reported by Michał Ż, fixed by Vetle L-R)
1518

0 commit comments

Comments
 (0)