package com.fasterxml.jackson.datatype.jsr310.deser;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.DateTimeException;
import java.time.Duration;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.core.JsonTokenId;
import com.fasterxml.jackson.core.StreamReadCapability;
import com.fasterxml.jackson.core.io.NumberInput;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import com.fasterxml.jackson.datatype.jsr310.DecimalUtils;
import com.fasterxml.jackson.datatype.jsr310.util.DurationUnitConverter;
public class DurationDeserializer extends JSR310DeserializerBase<Duration>
implements ContextualDeserializer
{
private static final long serialVersionUID = 1L;
public static final DurationDeserializer INSTANCE = new DurationDeserializer();
protected final DurationUnitConverter _durationUnitConverter;
public DurationDeserializer() {
super(Duration.class);
_durationUnitConverter = null;
}
protected DurationDeserializer(DurationDeserializer base, Boolean leniency) {
super(base, leniency);
_durationUnitConverter = base._durationUnitConverter;
}
protected DurationDeserializer(DurationDeserializer base, DurationUnitConverter converter) {
super(base, base._isLenient);
_durationUnitConverter = converter;
}
@Override
protected DurationDeserializer withLeniency(Boolean leniency) {
return new DurationDeserializer(this, leniency);
}
protected DurationDeserializer withConverter(DurationUnitConverter converter) {
return new DurationDeserializer(this, converter);
}
@Override
public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
BeanProperty property) throws JsonMappingException
{
JsonFormat.Value format = findFormatOverrides(ctxt, property, handledType());
DurationDeserializer deser = this;
if (format != null) {
if (format.hasLenient()) {
Boolean leniency = format.getLenient();
if (leniency != null) {
deser = deser.withLeniency(leniency);
}
}
if (format.hasPattern()) {
final String pattern = format.getPattern();
DurationUnitConverter p = DurationUnitConverter.from(pattern);
if (p == null) {
ctxt.reportBadDefinition(getValueType(ctxt),
String.format(
"Bad 'pattern' definition (\"%s\") for `Duration`: expected one of [%s]",
pattern, DurationUnitConverter.descForAllowed()));
}
deser = deser.withConverter(p);
}
}
return deser;
}
@Override
public Duration deserialize(JsonParser parser, DeserializationContext context) throws IOException
{
switch (parser.currentTokenId())
{
case JsonTokenId.ID_NUMBER_FLOAT:
BigDecimal value = parser.getDecimalValue();
return DecimalUtils.extractSecondsAndNanos(value, Duration::ofSeconds);
case JsonTokenId.ID_NUMBER_INT:
return _fromTimestamp(context, parser.getLongValue());
case JsonTokenId.ID_STRING:
return _fromString(parser, context, parser.getText());
case JsonTokenId.ID_START_OBJECT:
return _fromString(parser, context,
context.extractScalarFromObject(parser, this, handledType()));
case JsonTokenId.ID_EMBEDDED_OBJECT:
return (Duration) parser.getEmbeddedObject();
case JsonTokenId.ID_START_ARRAY:
return _deserializeFromArray(parser, context);
}
return _handleUnexpectedToken(context, parser, JsonToken.VALUE_STRING,
JsonToken.VALUE_NUMBER_INT, JsonToken.VALUE_NUMBER_FLOAT);
}
protected Duration _fromString(JsonParser parser, DeserializationContext ctxt,
String value0) throws IOException
{
String value = value0.trim();
if (value.length() == 0) {
return _fromEmptyString(parser, ctxt, value);
}
if (ctxt.isEnabled(StreamReadCapability.UNTYPED_SCALARS)
&& _isValidTimestampString(value)) {
return _fromTimestamp(ctxt, NumberInput.parseLong(value));
}
try {
return Duration.parse(value);
} catch (DateTimeException e) {
return _handleDateTimeException(ctxt, e, value);
}
}
protected Duration _fromTimestamp(DeserializationContext ctxt, long ts) {
if (_durationUnitConverter != null) {
return _durationUnitConverter.convert(ts);
}
if (ctxt.isEnabled(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS)) {
return Duration.ofSeconds(ts);
}
return Duration.ofMillis(ts);
}
}