package com.fasterxml.jackson.datatype.jsr310.deser;
import java.io.IOException;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.Locale;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonFormat.Feature;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import com.fasterxml.jackson.databind.util.ClassUtil;
@SuppressWarnings("serial")
public abstract class JSR310DateTimeDeserializerBase<T>
extends JSR310DeserializerBase<T>
implements ContextualDeserializer
{
protected final DateTimeFormatter _formatter;
protected final boolean _isLenient;
protected JSR310DateTimeDeserializerBase(Class<T> supportedType, DateTimeFormatter f) {
super(supportedType);
_formatter = f;
_isLenient = true;
}
protected JSR310DateTimeDeserializerBase(JSR310DateTimeDeserializerBase<T> base,
DateTimeFormatter f) {
super(base);
_formatter = f;
_isLenient = base._isLenient;
}
protected JSR310DateTimeDeserializerBase(JSR310DateTimeDeserializerBase<T> base,
Boolean leniency) {
super(base);
_formatter = base._formatter;
_isLenient = !Boolean.FALSE.equals(leniency);
}
protected abstract JSR310DateTimeDeserializerBase<T> withDateFormat(DateTimeFormatter dtf);
protected abstract JSR310DateTimeDeserializerBase<T> withLeniency(Boolean leniency);
@Override
public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
BeanProperty property) throws JsonMappingException
{
JsonFormat.Value format = findFormatOverrides(ctxt, property, handledType());
JSR310DateTimeDeserializerBase<?> deser = this;
if (format != null) {
if (format.hasPattern()) {
final String pattern = format.getPattern();
final Locale locale = format.hasLocale() ? format.getLocale() : ctxt.getLocale();
DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder();
if (acceptCaseInsensitiveValues(ctxt, format)) {
builder.parseCaseInsensitive();
}
builder.appendPattern(pattern);
DateTimeFormatter df;
if (locale == null) {
df = builder.toFormatter();
} else {
df = builder.toFormatter(locale);
}
if (format.hasTimeZone()) {
df = df.withZone(format.getTimeZone().toZoneId());
}
deser = deser.withDateFormat(df);
}
if (format.hasLenient()) {
Boolean leniency = format.getLenient();
if (leniency != null) {
deser = deser.withLeniency(leniency);
}
}
}
return deser;
}
protected boolean isLenient() {
return _isLenient;
}
private boolean acceptCaseInsensitiveValues(DeserializationContext ctxt, JsonFormat.Value format)
{
Boolean enabled = format.getFeature( Feature.ACCEPT_CASE_INSENSITIVE_VALUES);
if( enabled == null) {
enabled = ctxt.isEnabled(MapperFeature.ACCEPT_CASE_INSENSITIVE_VALUES);
}
return enabled;
}
protected void _throwNoNumericTimestampNeedTimeZone(JsonParser p, DeserializationContext ctxt)
throws IOException
{
ctxt.reportInputMismatch(handledType(),
"raw timestamp (%d) not allowed for `%s`: need additional information such as an offset or time-zone (see class Javadocs)",
p.getNumberValue(), handledType().getName());
}
@SuppressWarnings("unchecked")
protected T _failForNotLenient(JsonParser p, DeserializationContext ctxt,
JsonToken expToken) throws IOException
{
return (T) ctxt.handleUnexpectedToken(handledType(), expToken, p,
"Cannot deserialize instance of %s out of %s token: not allowed because 'strict' mode set for property or type (enable 'lenient' handling to allow)",
ClassUtil.nameOf(handledType()), p.currentToken());
}
}