1
16
17 package com.fasterxml.jackson.datatype.jsr310.deser;
18
19 import java.io.IOException;
20 import java.time.DateTimeException;
21 import java.time.Instant;
22 import java.time.LocalDate;
23 import java.time.LocalDateTime;
24 import java.time.ZoneOffset;
25 import java.time.format.DateTimeFormatter;
26
27 import com.fasterxml.jackson.annotation.JsonFormat;
28 import com.fasterxml.jackson.core.*;
29 import com.fasterxml.jackson.databind.DeserializationContext;
30 import com.fasterxml.jackson.databind.DeserializationFeature;
31
32
37 public class LocalDateDeserializer extends JSR310DateTimeDeserializerBase<LocalDate>
38 {
39 private static final long serialVersionUID = 1L;
40
41 private static final DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE;
42
43 public static final LocalDateDeserializer INSTANCE = new LocalDateDeserializer();
44
45 protected LocalDateDeserializer() {
46 this(DEFAULT_FORMATTER);
47 }
48
49 public LocalDateDeserializer(DateTimeFormatter dtf) {
50 super(LocalDate.class, dtf);
51 }
52
53
56 public LocalDateDeserializer(LocalDateDeserializer base, DateTimeFormatter dtf) {
57 super(base, dtf);
58 }
59
60
63 protected LocalDateDeserializer(LocalDateDeserializer base, Boolean leniency) {
64 super(base, leniency);
65 }
66
67
70 protected LocalDateDeserializer(LocalDateDeserializer base, JsonFormat.Shape shape) {
71 super(base, shape);
72 }
73
74 @Override
75 protected LocalDateDeserializer withDateFormat(DateTimeFormatter dtf) {
76 return new LocalDateDeserializer(this, dtf);
77 }
78
79 @Override
80 protected LocalDateDeserializer withLeniency(Boolean leniency) {
81 return new LocalDateDeserializer(this, leniency);
82 }
83
84 @Override
85 protected LocalDateDeserializer withShape(JsonFormat.Shape shape) { return new LocalDateDeserializer(this, shape); }
86
87 @Override
88 public LocalDate deserialize(JsonParser parser, DeserializationContext context) throws IOException
89 {
90 if (parser.hasToken(JsonToken.VALUE_STRING)) {
91 String string = parser.getText().trim();
92 if (string.length() == 0) {
93 if (!isLenient()) {
94 return _failForNotLenient(parser, context, JsonToken.VALUE_STRING);
95 }
96 return null;
97 }
98
99
100 DateTimeFormatter format = _formatter;
101 try {
102 if (format == DEFAULT_FORMATTER) {
103
104 if (string.length() > 10 && string.charAt(10) == 'T') {
105 if (string.endsWith("Z")) {
106 return LocalDateTime.ofInstant(Instant.parse(string), ZoneOffset.UTC).toLocalDate();
107 } else {
108 return LocalDate.parse(string, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
109 }
110 }
111 }
112 return LocalDate.parse(string, format);
113 } catch (DateTimeException e) {
114 return _handleDateTimeException(context, e, string);
115 }
116 }
117 if (parser.isExpectedStartArrayToken()) {
118 JsonToken t = parser.nextToken();
119 if (t == JsonToken.END_ARRAY) {
120 return null;
121 }
122 if (context.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)
123 && (t == JsonToken.VALUE_STRING || t==JsonToken.VALUE_EMBEDDED_OBJECT)) {
124 final LocalDate parsed = deserialize(parser, context);
125 if (parser.nextToken() != JsonToken.END_ARRAY) {
126 handleMissingEndArrayForSingle(parser, context);
127 }
128 return parsed;
129 }
130 if (t == JsonToken.VALUE_NUMBER_INT) {
131 int year = parser.getIntValue();
132 int month = parser.nextIntValue(-1);
133 int day = parser.nextIntValue(-1);
134
135 if (parser.nextToken() != JsonToken.END_ARRAY) {
136 throw context.wrongTokenException(parser, handledType(), JsonToken.END_ARRAY,
137 "Expected array to end");
138 }
139 return LocalDate.of(year, month, day);
140 }
141 context.reportInputMismatch(handledType(),
142 "Unexpected token (%s) within Array, expected VALUE_NUMBER_INT",
143 t);
144 }
145 if (parser.hasToken(JsonToken.VALUE_EMBEDDED_OBJECT)) {
146 return (LocalDate) parser.getEmbeddedObject();
147 }
148
149 if (parser.hasToken(JsonToken.VALUE_NUMBER_INT)) {
150
151 if (_shape == JsonFormat.Shape.NUMBER_INT || isLenient()) {
152 return LocalDate.ofEpochDay(parser.getLongValue());
153 }
154 return _failForNotLenient(parser, context, JsonToken.VALUE_STRING);
155 }
156 return _handleUnexpectedToken(context, parser, "Expected array or string.");
157 }
158 }
159