package com.fasterxml.jackson.datatype.jsr310.ser;
import java.lang.reflect.Type;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonFormat.Shape;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonArrayFormatVisitor;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatTypes;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonStringFormatVisitor;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonValueFormat;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
abstract class JSR310FormattedSerializerBase<T>
extends JSR310SerializerBase<T>
implements ContextualSerializer
{
private static final long serialVersionUID = 1L;
protected final Boolean _useTimestamp;
protected final Boolean _useNanoseconds;
protected final DateTimeFormatter _formatter;
protected final JsonFormat.Shape _shape;
protected JSR310FormattedSerializerBase(Class<T> supportedType) {
this(supportedType, null);
}
protected JSR310FormattedSerializerBase(Class<T> supportedType,
DateTimeFormatter formatter) {
super(supportedType);
_useTimestamp = null;
_useNanoseconds = null;
_shape = null;
_formatter = formatter;
}
protected JSR310FormattedSerializerBase(JSR310FormattedSerializerBase<?> base,
Boolean useTimestamp, DateTimeFormatter dtf, JsonFormat.Shape shape)
{
this(base, useTimestamp, null, dtf, shape);
}
protected JSR310FormattedSerializerBase(JSR310FormattedSerializerBase<?> base,
Boolean useTimestamp, Boolean useNanoseconds, DateTimeFormatter dtf,
JsonFormat.Shape shape)
{
super(base.handledType());
_useTimestamp = useTimestamp;
_useNanoseconds = useNanoseconds;
_formatter = dtf;
_shape = shape;
}
protected abstract JSR310FormattedSerializerBase<?> withFormat(Boolean useTimestamp,
DateTimeFormatter dtf, JsonFormat.Shape shape);
@Deprecated
protected JSR310FormattedSerializerBase<?> withFeatures(Boolean writeZoneId) {
return this;
}
protected JSR310FormattedSerializerBase<?> withFeatures(Boolean writeZoneId,
Boolean writeNanoseconds) {
return this;
}
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov,
BeanProperty property) throws JsonMappingException
{
JsonFormat.Value format = findFormatOverrides(prov, property, handledType());
if (format != null) {
Boolean useTimestamp = null;
JsonFormat.Shape shape = format.getShape();
if (shape == JsonFormat.Shape.ARRAY || shape.isNumeric() ) {
useTimestamp = Boolean.TRUE;
} else {
useTimestamp = (shape == JsonFormat.Shape.STRING) ? Boolean.FALSE : null;
}
DateTimeFormatter dtf = _formatter;
if (format.hasPattern()) {
final String pattern = format.getPattern();
final Locale locale = format.hasLocale() ? format.getLocale() : prov.getLocale();
if (locale == null) {
dtf = DateTimeFormatter.ofPattern(pattern);
} else {
dtf = DateTimeFormatter.ofPattern(pattern, locale);
}
if (format.hasTimeZone()) {
dtf = dtf.withZone(format.getTimeZone().toZoneId());
}
}
JSR310FormattedSerializerBase<?> ser = this;
if ((shape != _shape) || (useTimestamp != _useTimestamp) || (dtf != _formatter)) {
ser = ser.withFormat(useTimestamp, dtf, shape);
}
Boolean writeZoneId = format.getFeature(JsonFormat.Feature.WRITE_DATES_WITH_ZONE_ID);
Boolean writeNanoseconds = format.getFeature(JsonFormat.Feature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS);
if ((writeZoneId != null) || (writeNanoseconds != null)) {
ser = ser.withFeatures(writeZoneId, writeNanoseconds);
}
return ser;
}
return this;
}
@Override
public JsonNode getSchema(SerializerProvider provider, Type typeHint)
{
return createSchemaNode(
provider.isEnabled(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) ? "array" : "string", true
);
}
@Override
public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType typeHint) throws JsonMappingException
{
SerializerProvider provider = visitor.getProvider();
boolean useTimestamp = (provider != null) && useTimestamp(provider);
if (useTimestamp) {
_acceptTimestampVisitor(visitor, typeHint);
} else {
JsonStringFormatVisitor v2 = visitor.expectStringFormat(typeHint);
if (v2 != null) {
v2.format(JsonValueFormat.DATE_TIME);
}
}
}
protected void _acceptTimestampVisitor(JsonFormatVisitorWrapper visitor, JavaType typeHint) throws JsonMappingException
{
JsonArrayFormatVisitor v2 = visitor.expectArrayFormat(typeHint);
if (v2 != null) {
v2.itemsFormat(JsonFormatTypes.INTEGER);
}
}
protected boolean useTimestamp(SerializerProvider provider) {
if (_useTimestamp != null) {
return _useTimestamp.booleanValue();
}
if (_shape != null) {
if (_shape == Shape.STRING) {
return false;
}
if (_shape == Shape.NUMBER_INT) {
return true;
}
}
return _formatter == null && provider.isEnabled(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
}
protected boolean _useTimestampExplicitOnly(SerializerProvider provider) {
if (_useTimestamp != null) {
return _useTimestamp.booleanValue();
}
return false;
}
protected boolean useNanoseconds(SerializerProvider provider) {
if (_useNanoseconds != null) {
return _useNanoseconds.booleanValue();
}
if (_shape != null) {
if (_shape == Shape.NUMBER_INT) {
return false;
}
if (_shape == Shape.NUMBER_FLOAT) {
return true;
}
}
return provider.isEnabled(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS);
}
}