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