DateBasedDeserializer.java
package tools.jackson.databind.deser.jdk;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Locale;
import java.util.TimeZone;
import com.fasterxml.jackson.annotation.JsonFormat;
import tools.jackson.core.JacksonException;
import tools.jackson.core.JsonParser;
import tools.jackson.core.JsonToken;
import tools.jackson.databind.BeanProperty;
import tools.jackson.databind.DeserializationContext;
import tools.jackson.databind.ValueDeserializer;
import tools.jackson.databind.cfg.CoercionAction;
import tools.jackson.databind.deser.std.StdScalarDeserializer;
import tools.jackson.databind.type.LogicalType;
import tools.jackson.databind.util.StdDateFormat;
public abstract class DateBasedDeserializer<T>
extends StdScalarDeserializer<T>
{
/**
* Specific format to use, if non-null; if null will
* just use default format.
*/
protected final DateFormat _customFormat;
/**
* Let's also keep format String for reference, to use for error messages
*/
protected final String _formatString;
protected DateBasedDeserializer(Class<?> clz) {
super(clz);
_customFormat = null;
_formatString = null;
}
protected DateBasedDeserializer(DateBasedDeserializer<T> base,
DateFormat format, String formatStr) {
super(base._valueClass);
_customFormat = format;
_formatString = formatStr;
}
protected abstract DateBasedDeserializer<T> withDateFormat(DateFormat df, String formatStr);
@Override // since 2.12
public LogicalType logicalType() {
return LogicalType.DateTime;
}
@Override
public ValueDeserializer<?> createContextual(DeserializationContext ctxt,
BeanProperty property)
{
final JsonFormat.Value format = findFormatOverrides(ctxt, property,
handledType());
if (format != null) {
TimeZone tz = format.getTimeZone();
final Boolean lenient = format.getLenient();
// First: fully custom pattern?
if (format.hasPattern()) {
final String pattern = format.getPattern();
final Locale loc = format.hasLocale() ? format.getLocale() : ctxt.getLocale();
SimpleDateFormat df = new SimpleDateFormat(pattern, loc);
if (tz == null) {
tz = ctxt.getTimeZone();
}
df.setTimeZone(tz);
if (lenient != null) {
df.setLenient(lenient);
}
return withDateFormat(df, pattern);
}
// But if not, can still override timezone
if (tz != null) {
DateFormat df = ctxt.getConfig().getDateFormat();
// one shortcut: with our custom format, can simplify handling a bit
if (df.getClass() == StdDateFormat.class) {
final Locale loc = format.hasLocale() ? format.getLocale() : ctxt.getLocale();
StdDateFormat std = (StdDateFormat) df;
std = std.withTimeZone(tz);
std = std.withLocale(loc);
if (lenient != null) {
std = std.withLenient(lenient);
}
df = std;
} else {
// otherwise need to clone, re-set timezone:
df = (DateFormat) df.clone();
df.setTimeZone(tz);
if (lenient != null) {
df.setLenient(lenient);
}
}
return withDateFormat(df, _formatString);
}
// or maybe even just leniency?
if (lenient != null) {
DateFormat df = ctxt.getConfig().getDateFormat();
String pattern = _formatString;
// one shortcut: with our custom format, can simplify handling a bit
if (df.getClass() == StdDateFormat.class) {
StdDateFormat std = (StdDateFormat) df;
std = std.withLenient(lenient);
df = std;
pattern = std.toPattern();
} else {
// otherwise need to clone,
df = (DateFormat) df.clone();
df.setLenient(lenient);
if (df instanceof SimpleDateFormat sdf) {
sdf.toPattern();
}
}
if (pattern == null) {
pattern = "[unknown]";
}
return withDateFormat(df, pattern);
}
}
return this;
}
@Override
protected java.util.Date _parseDate(JsonParser p, DeserializationContext ctxt)
throws JacksonException
{
if (_customFormat != null) {
if (p.hasToken(JsonToken.VALUE_STRING)) {
String str = p.getString().trim();
if (str.isEmpty()) {
final CoercionAction act = _checkFromStringCoercion(ctxt, str);
switch (act) { // note: Fail handled above
case AsEmpty:
return new java.util.Date(0L);
case AsNull:
case TryConvert:
default:
}
return null;
}
synchronized (_customFormat) {
try {
return _customFormat.parse(str);
} catch (ParseException e) {
return (java.util.Date) ctxt.handleWeirdStringValue(handledType(), str,
"expected format \"%s\"", _formatString);
}
}
}
}
return super._parseDate(p, ctxt);
}
}