Skip to content

issue 58 - NUMBER_INT should be specified when deserializing LocalDate as EpochDays #139

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,10 @@ protected InstantDeserializer<T> withDateFormat(DateTimeFormatter dtf) {
protected InstantDeserializer<T> withLeniency(Boolean leniency) {
return this;
}


@Override
protected JSR310DateTimeDeserializerBase<T> withShape(JsonFormat.Shape shape) { return this; }

@SuppressWarnings("unchecked")
@Override
public T deserialize(JsonParser parser, DeserializationContext context) throws IOException
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonFormat.Feature;
import com.fasterxml.jackson.annotation.JsonFormat.Shape;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.BeanProperty;
Expand Down Expand Up @@ -34,28 +35,53 @@ public abstract class JSR310DateTimeDeserializerBase<T>
*/
protected final boolean _isLenient;

/**
* Setting that indicates the {@Link JsonFormat.Shape} specified for this deserializer
* as a {@link JsonFormat.Shape} annotation on property or class, or due to per-type
* "config override", or from global settings:
* If Shape is NUMBER_INT, the input value is considered to be epoch days. If not a
* NUMBER_INT, and the deserializer was not specified with the leniency setting of true,
* then an exception will be thrown.
* @see [jackson-modules-java8#58] for more info
*
* @since 2.10
*/
protected final Shape _shape;

protected JSR310DateTimeDeserializerBase(Class<T> supportedType, DateTimeFormatter f) {
super(supportedType);
_formatter = f;
_isLenient = true;
_shape = null;
}

protected JSR310DateTimeDeserializerBase(JSR310DateTimeDeserializerBase<T> base,
DateTimeFormatter f) {
super(base);
_formatter = f;
_isLenient = base._isLenient;
_shape = base._shape;
}

protected JSR310DateTimeDeserializerBase(JSR310DateTimeDeserializerBase<T> base,
Boolean leniency) {
super(base);
_formatter = base._formatter;
_shape = base._shape;
_isLenient = !Boolean.FALSE.equals(leniency);
}

protected JSR310DateTimeDeserializerBase(JSR310DateTimeDeserializerBase<T> base,
Shape shape) {
super(base);
_formatter = base._formatter;
_shape = shape;
_isLenient = base._isLenient;
}

protected abstract JSR310DateTimeDeserializerBase<T> withDateFormat(DateTimeFormatter dtf);
protected abstract JSR310DateTimeDeserializerBase<T> withLeniency(Boolean leniency);
protected abstract JSR310DateTimeDeserializerBase<T> withShape(Shape shape);

@Override
public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
Expand Down Expand Up @@ -92,6 +118,10 @@ public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
deser = deser.withLeniency(leniency);
}
}
Shape shape = format.getShape();
if (shape != null && shape != _shape) {
deser = deser.withShape(shape);
}
// any use for TimeZone?
}
return deser;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.DeserializationFeature;
Expand Down Expand Up @@ -61,6 +62,13 @@ protected LocalDateDeserializer(LocalDateDeserializer base, Boolean leniency) {
super(base, leniency);
}

/**
* Since 2.9.10
*/
protected LocalDateDeserializer(LocalDateDeserializer base, JsonFormat.Shape shape) {
super(base, shape);
}

@Override
protected LocalDateDeserializer withDateFormat(DateTimeFormatter dtf) {
return new LocalDateDeserializer(this, dtf);
Expand All @@ -71,6 +79,9 @@ protected LocalDateDeserializer withLeniency(Boolean leniency) {
return new LocalDateDeserializer(this, leniency);
}

@Override
protected JSR310DateTimeDeserializerBase<LocalDate> withShape(JsonFormat.Shape shape) { return new LocalDateDeserializer(this, shape); }

@Override
public LocalDate deserialize(JsonParser parser, DeserializationContext context) throws IOException
{
Expand Down Expand Up @@ -134,10 +145,11 @@ public LocalDate deserialize(JsonParser parser, DeserializationContext context)
}
// 06-Jan-2018, tatu: Is this actually safe? Do users expect such coercion?
if (parser.hasToken(JsonToken.VALUE_NUMBER_INT)) {
if (!isLenient()) {
return _failForNotLenient(parser, context, JsonToken.VALUE_STRING);
// issue 58 - also check for NUMBER_INT, which needs to be specified when serializing.
if (_shape == JsonFormat.Shape.NUMBER_INT || isLenient()) {
return LocalDate.ofEpochDay(parser.getLongValue());
}
return LocalDate.ofEpochDay(parser.getLongValue());
return _failForNotLenient(parser, context, JsonToken.VALUE_STRING);
}
return _handleUnexpectedToken(context, parser, "Expected array or string.");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.core.JsonTokenId;
Expand Down Expand Up @@ -66,6 +67,9 @@ protected LocalDateTimeDeserializer withLeniency(Boolean leniency) {
return new LocalDateTimeDeserializer(this, leniency);
}

@Override
protected JSR310DateTimeDeserializerBase<LocalDateTime> withShape(JsonFormat.Shape shape) { return this; }

@Override
public LocalDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
Expand Down Expand Up @@ -56,6 +57,9 @@ protected LocalTimeDeserializer withLeniency(Boolean leniency) {
return this;
}

@Override
protected JSR310DateTimeDeserializerBase<LocalTime> withShape(JsonFormat.Shape shape) { return this; }

@Override
public LocalTime deserialize(JsonParser parser, DeserializationContext context) throws IOException
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.time.MonthDay;
import java.time.format.DateTimeFormatter;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
Expand Down Expand Up @@ -32,6 +33,9 @@ protected MonthDayDeserializer withLeniency(Boolean leniency) {
return this;
}

@Override
protected JSR310DateTimeDeserializerBase<MonthDay> withShape(JsonFormat.Shape shape) { return this; }

@Override
public MonthDay deserialize(JsonParser parser, DeserializationContext context) throws IOException
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;

Expand Down Expand Up @@ -53,6 +54,9 @@ protected OffsetTimeDeserializer withLeniency(Boolean leniency) {
return this;
}

@Override
protected JSR310DateTimeDeserializerBase<OffsetTime> withShape(JsonFormat.Shape shape) { return this; }

@Override
public OffsetTime deserialize(JsonParser parser, DeserializationContext context) throws IOException
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

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

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
Expand Down Expand Up @@ -54,6 +55,9 @@ protected YearDeserializer withLeniency(Boolean leniency) {
return this;
}

@Override
protected JSR310DateTimeDeserializerBase<Year> withShape(JsonFormat.Shape shape) { return this; }

@Override
public Year deserialize(JsonParser parser, DeserializationContext context) throws IOException
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.DeserializationFeature;
Expand Down Expand Up @@ -57,6 +58,9 @@ protected YearMonthDeserializer withLeniency(Boolean leniency) {
return this;
}

@Override
protected JSR310DateTimeDeserializerBase<YearMonth> withShape(JsonFormat.Shape shape) { return this; }

@Override
public YearMonth deserialize(JsonParser parser, DeserializationContext context) throws IOException
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,15 @@ final static class Wrapper {
public Wrapper() { }
public Wrapper(LocalDate v) { value = v; }
}


final static class ShapeWrapper {
@JsonFormat(shape=JsonFormat.Shape.NUMBER_INT)
public LocalDate date;

public ShapeWrapper() { }
public ShapeWrapper(LocalDate v) { date = v; }
}

/*
/**********************************************************
/* Deserialization from Int array representation
Expand Down Expand Up @@ -161,7 +169,7 @@ public void testLenientDeserializeFromInt() throws Exception

// But with alternate setting, not so
@Test
public void testStricDeserializeFromInt() throws Exception
public void testStrictDeserializeFromInt() throws Exception
{
ObjectMapper mapper = mapperBuilder()
.withConfigOverride(LocalDate.class,
Expand All @@ -180,6 +188,46 @@ public void testStricDeserializeFromInt() throws Exception
// be content with just one...
}

@Test
public void testLenientDeserializeFromNumberInt() throws Exception
{
ObjectMapper mapper = newMapperBuilder()
.withConfigOverride(LocalDate.class,
o -> o.setFormat(JsonFormat.Value.forShape(JsonFormat.Shape.NUMBER_INT)))
.build();

assertEquals("The value is not correct.", LocalDate.of(1970, Month.MAY, 04),
mapper.readValue("123", LocalDate.class));
}

@Test
public void testStrictDeserializeFromNumberInt() throws Exception
{
ObjectMapper mapper = newMapperBuilder()
.withConfigOverride(LocalDate.class,
c -> c.setFormat(JsonFormat.Value.forLeniency(false))
)
.build();

ShapeWrapper w = mapper.readValue("{\"date\":123}", ShapeWrapper.class);
LocalDate localDate = w.date;

assertEquals("The value is not correct.", LocalDate.of(1970, Month.MAY, 04),
localDate);
}

@Test(expected = MismatchedInputException.class)
public void testStrictDeserializeFromString() throws Exception
{
ObjectMapper mapper = newMapperBuilder()
.withConfigOverride(LocalDate.class,
c -> c.setFormat(JsonFormat.Value.forLeniency(false))
)
.build();

mapper.readValue("{\"value\":123}", Wrapper.class);
}

/*
/**********************************************************
/* Tests for empty string handling
Expand Down