1 package com.fasterxml.jackson.databind.deser.std;
2
3 import java.io.IOException;
4 import java.lang.reflect.Constructor;
5 import java.sql.Timestamp;
6 import java.text.*;
7 import java.util.*;
8
9 import com.fasterxml.jackson.annotation.JsonFormat;
10
11 import com.fasterxml.jackson.core.JsonParser;
12 import com.fasterxml.jackson.core.JsonToken;
13
14 import com.fasterxml.jackson.databind.*;
15 import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
16 import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
17 import com.fasterxml.jackson.databind.util.ClassUtil;
18 import com.fasterxml.jackson.databind.util.StdDateFormat;
19
20
23 @SuppressWarnings("serial")
24 public class DateDeserializers
25 {
26 private final static HashSet<String> _classNames = new HashSet<String>();
27 static {
28 Class<?>[] numberTypes = new Class<?>[] {
29 Calendar.class,
30 GregorianCalendar.class,
31 java.sql.Date.class,
32 java.util.Date.class,
33 Timestamp.class,
34 };
35 for (Class<?> cls : numberTypes) {
36 _classNames.add(cls.getName());
37 }
38 }
39
40 public static JsonDeserializer<?> find(Class<?> rawType, String clsName)
41 {
42 if (_classNames.contains(clsName)) {
43
44 if (rawType == Calendar.class) {
45 return new CalendarDeserializer();
46 }
47 if (rawType == java.util.Date.class) {
48 return DateDeserializer.instance;
49 }
50 if (rawType == java.sql.Date.class) {
51 return new SqlDateDeserializer();
52 }
53 if (rawType == Timestamp.class) {
54 return new TimestampDeserializer();
55 }
56 if (rawType == GregorianCalendar.class) {
57 return new CalendarDeserializer(GregorianCalendar.class);
58 }
59 }
60 return null;
61 }
62
63
64 public static boolean hasDeserializerFor(Class<?> rawType) {
65 return _classNames.contains(rawType.getName());
66 }
67
68
73
74 protected abstract static class DateBasedDeserializer<T>
75 extends StdScalarDeserializer<T>
76 implements ContextualDeserializer
77 {
78
82 protected final DateFormat _customFormat;
83
84
87 protected final String _formatString;
88
89 protected DateBasedDeserializer(Class<?> clz) {
90 super(clz);
91 _customFormat = null;
92 _formatString = null;
93 }
94
95 protected DateBasedDeserializer(DateBasedDeserializer<T> base,
96 DateFormat format, String formatStr) {
97 super(base._valueClass);
98 _customFormat = format;
99 _formatString = formatStr;
100 }
101
102 protected abstract DateBasedDeserializer<T> withDateFormat(DateFormat df, String formatStr);
103
104 @Override
105 public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
106 BeanProperty property)
107 throws JsonMappingException
108 {
109 final JsonFormat.Value format = findFormatOverrides(ctxt, property,
110 handledType());
111
112 if (format != null) {
113 TimeZone tz = format.getTimeZone();
114 final Boolean lenient = format.getLenient();
115
116
117 if (format.hasPattern()) {
118 final String pattern = format.getPattern();
119 final Locale loc = format.hasLocale() ? format.getLocale() : ctxt.getLocale();
120 SimpleDateFormat df = new SimpleDateFormat(pattern, loc);
121 if (tz == null) {
122 tz = ctxt.getTimeZone();
123 }
124 df.setTimeZone(tz);
125 if (lenient != null) {
126 df.setLenient(lenient);
127 }
128 return withDateFormat(df, pattern);
129 }
130
131 if (tz != null) {
132 DateFormat df = ctxt.getConfig().getDateFormat();
133
134 if (df.getClass() == StdDateFormat.class) {
135 final Locale loc = format.hasLocale() ? format.getLocale() : ctxt.getLocale();
136 StdDateFormat std = (StdDateFormat) df;
137 std = std.withTimeZone(tz);
138 std = std.withLocale(loc);
139 if (lenient != null) {
140 std = std.withLenient(lenient);
141 }
142 df = std;
143 } else {
144
145 df = (DateFormat) df.clone();
146 df.setTimeZone(tz);
147 if (lenient != null) {
148 df.setLenient(lenient);
149 }
150 }
151 return withDateFormat(df, _formatString);
152 }
153
154 if (lenient != null) {
155 DateFormat df = ctxt.getConfig().getDateFormat();
156 String pattern = _formatString;
157
158 if (df.getClass() == StdDateFormat.class) {
159 StdDateFormat std = (StdDateFormat) df;
160 std = std.withLenient(lenient);
161 df = std;
162 pattern = std.toPattern();
163 } else {
164
165 df = (DateFormat) df.clone();
166 df.setLenient(lenient);
167 if (df instanceof SimpleDateFormat) {
168 ((SimpleDateFormat) df).toPattern();
169 }
170 }
171 if (pattern == null) {
172 pattern = "[unknown]";
173 }
174 return withDateFormat(df, pattern);
175 }
176 }
177 return this;
178 }
179
180 @Override
181 protected java.util.Date _parseDate(JsonParser p, DeserializationContext ctxt)
182 throws IOException
183 {
184 if (_customFormat != null) {
185 if (p.hasToken(JsonToken.VALUE_STRING)) {
186 String str = p.getText().trim();
187 if (str.length() == 0) {
188 return (Date) getEmptyValue(ctxt);
189 }
190 synchronized (_customFormat) {
191 try {
192 return _customFormat.parse(str);
193 } catch (ParseException e) {
194 return (java.util.Date) ctxt.handleWeirdStringValue(handledType(), str,
195 "expected format \"%s\"", _formatString);
196 }
197 }
198 }
199 }
200 return super._parseDate(p, ctxt);
201 }
202 }
203
204
209
210 @JacksonStdImpl
211 public static class CalendarDeserializer extends DateBasedDeserializer<Calendar>
212 {
213
219 protected final Constructor<Calendar> _defaultCtor;
220
221 public CalendarDeserializer() {
222 super(Calendar.class);
223 _defaultCtor = null;
224 }
225
226 @SuppressWarnings("unchecked")
227 public CalendarDeserializer(Class<? extends Calendar> cc) {
228 super(cc);
229 _defaultCtor = (Constructor<Calendar>) ClassUtil.findConstructor(cc, false);
230 }
231
232 public CalendarDeserializer(CalendarDeserializer src, DateFormat df, String formatString) {
233 super(src, df, formatString);
234 _defaultCtor = src._defaultCtor;
235 }
236
237 @Override
238 protected CalendarDeserializer withDateFormat(DateFormat df, String formatString) {
239 return new CalendarDeserializer(this, df, formatString);
240 }
241
242 @Override
243 public Calendar deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
244 {
245 Date d = _parseDate(p, ctxt);
246 if (d == null) {
247 return null;
248 }
249 if (_defaultCtor == null) {
250 return ctxt.constructCalendar(d);
251 }
252 try {
253 Calendar c = _defaultCtor.newInstance();
254 c.setTimeInMillis(d.getTime());
255 TimeZone tz = ctxt.getTimeZone();
256 if (tz != null) {
257 c.setTimeZone(tz);
258 }
259 return c;
260 } catch (Exception e) {
261 return (Calendar) ctxt.handleInstantiationProblem(handledType(), d, e);
262 }
263 }
264 }
265
266
273 @JacksonStdImpl
274 public static class DateDeserializer extends DateBasedDeserializer<Date>
275 {
276 public final static DateDeserializer instance = new DateDeserializer();
277
278 public DateDeserializer() { super(Date.class); }
279 public DateDeserializer(DateDeserializer base, DateFormat df, String formatString) {
280 super(base, df, formatString);
281 }
282
283 @Override
284 protected DateDeserializer withDateFormat(DateFormat df, String formatString) {
285 return new DateDeserializer(this, df, formatString);
286 }
287
288 @Override
289 public java.util.Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
290 return _parseDate(p, ctxt);
291 }
292 }
293
294
298 public static class SqlDateDeserializer
299 extends DateBasedDeserializer<java.sql.Date>
300 {
301 public SqlDateDeserializer() { super(java.sql.Date.class); }
302 public SqlDateDeserializer(SqlDateDeserializer src, DateFormat df, String formatString) {
303 super(src, df, formatString);
304 }
305
306 @Override
307 protected SqlDateDeserializer withDateFormat(DateFormat df, String formatString) {
308 return new SqlDateDeserializer(this, df, formatString);
309 }
310
311 @Override
312 public java.sql.Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
313 Date d = _parseDate(p, ctxt);
314 return (d == null) ? null : new java.sql.Date(d.getTime());
315 }
316 }
317
318
325 public static class TimestampDeserializer extends DateBasedDeserializer<Timestamp>
326 {
327 public TimestampDeserializer() { super(Timestamp.class); }
328 public TimestampDeserializer(TimestampDeserializer src, DateFormat df, String formatString) {
329 super(src, df, formatString);
330 }
331
332 @Override
333 protected TimestampDeserializer withDateFormat(DateFormat df, String formatString) {
334 return new TimestampDeserializer(this, df, formatString);
335 }
336
337 @Override
338 public java.sql.Timestamp deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
339 {
340 Date d = _parseDate(p, ctxt);
341 return (d == null) ? null : new Timestamp(d.getTime());
342 }
343 }
344 }
345