package com.fasterxml.jackson.databind.ser.std; import java.io.IOException; import java.lang.reflect.Type; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Locale; import java.util.TimeZone; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.core.JsonGenerationException; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.introspect.Annotated; import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper; import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonValueFormat; import com.fasterxml.jackson.databind.ser.ContextualSerializer; import com.fasterxml.jackson.databind.util.StdDateFormat; public abstract class DateTimeSerializerBase<T> extends StdScalarSerializer<T> implements ContextualSerializer { /** * Flag that indicates that serialization must be done as the * Java timetamp, regardless of other settings. */ protected final boolean _useTimestamp; /** * Specific format to use, if not default format: non null value * also indicates that serialization is to be done as JSON String, * not numeric timestamp, unless {@link #_useTimestamp} is true. */ protected final DateFormat _customFormat; protected DateTimeSerializerBase(Class<T> type, boolean useTimestamp, DateFormat customFormat) { super(type); _useTimestamp = useTimestamp; _customFormat = customFormat; } public abstract DateTimeSerializerBase<T> withFormat(boolean timestamp, DateFormat customFormat); // @Override public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException { if (property != null) { JsonFormat.Value format = prov.getAnnotationIntrospector().findFormat((Annotated)property.getMember()); if (format != null) { // Simple case first: serialize as numeric timestamp? if (format.getShape().isNumeric()) { return withFormat(true, null); } // If not, do we have a pattern? TimeZone tz = format.getTimeZone(); String pattern = format.getPattern(); if (pattern.length() > 0){ Locale loc = format.getLocale(); if (loc == null) { loc = prov.getLocale(); } SimpleDateFormat df = new SimpleDateFormat(pattern, loc); if (tz == null) { tz = prov.getTimeZone(); } df.setTimeZone(tz); return withFormat(false, df); } // If not, do we at least have a custom timezone? if (tz != null) { DateFormat df = prov.getConfig().getDateFormat(); // one shortcut: with our custom format, can simplify handling a bit if (df.getClass() == StdDateFormat.class) { df = StdDateFormat.getISO8601Format(tz); } else { // otherwise need to clone, re-set timezone: df = (DateFormat) df.clone(); df.setTimeZone(tz); } return withFormat(false, df); } } } return this; } /* /********************************************************** /* Accessors /********************************************************** */ @Override public boolean isEmpty(T value) { // let's assume "null date" (timestamp 0) qualifies for empty return (value == null) || (_timestamp(value) == 0L); } protected abstract long _timestamp(T value); @Override public JsonNode getSchema(SerializerProvider provider, Type typeHint) { //todo: (ryan) add a format for the date in the schema? boolean asNumber = _useTimestamp; if (!asNumber) { if (_customFormat == null) { asNumber = provider.isEnabled(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); } } return createSchemaNode(asNumber ? "number" : "string", true); } @Override public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType typeHint) { //todo: (ryan) add a format for the date in the schema? boolean asNumber = _useTimestamp; if (!asNumber) { if (_customFormat == null) { asNumber = visitor.getProvider().isEnabled(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); } } if (asNumber) { visitor.expectNumberFormat(typeHint).format(JsonValueFormat.UTC_MILLISEC); } else { visitor.expectStringFormat(typeHint).format(JsonValueFormat.DATE_TIME); } } /* /********************************************************** /* Actual serialization /********************************************************** */ @Override public abstract void serialize(T value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException; }