1 /*
2  * Copyright 2013 FasterXML.com
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may
5  * not use this file except in compliance with the License. You may obtain
6  * a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the license for the specific language governing permissions and
14  * limitations under the license.
15  */

16
17 package com.fasterxml.jackson.datatype.jsr310.deser;
18
19 import java.io.IOException;
20 import java.time.DateTimeException;
21 import java.time.LocalTime;
22 import java.time.format.DateTimeFormatter;
23
24 import com.fasterxml.jackson.annotation.JsonFormat;
25 import com.fasterxml.jackson.core.JsonParser;
26 import com.fasterxml.jackson.core.JsonToken;
27 import com.fasterxml.jackson.databind.DeserializationContext;
28 import com.fasterxml.jackson.databind.DeserializationFeature;
29
30 /**
31  * Deserializer for Java 8 temporal {@link LocalTime}s.
32  *
33  * @author Nick Williams
34  */

35 public class LocalTimeDeserializer extends JSR310DateTimeDeserializerBase<LocalTime>
36 {
37     private static final long serialVersionUID = 1L;
38     
39     private static final DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormatter.ISO_LOCAL_TIME;
40
41     public static final LocalTimeDeserializer INSTANCE = new LocalTimeDeserializer();
42
43     private LocalTimeDeserializer() {
44         this(DEFAULT_FORMATTER);
45     }
46
47     public LocalTimeDeserializer(DateTimeFormatter formatter) {
48         super(LocalTime.class, formatter);
49     }
50
51     /**
52      * Since 2.11
53      */

54     protected LocalTimeDeserializer(LocalTimeDeserializer base, Boolean leniency) {
55         super(base, leniency);
56     }
57
58     @Override
59     protected LocalTimeDeserializer withDateFormat(DateTimeFormatter formatter) {
60         return new LocalTimeDeserializer(formatter);
61     }
62
63     @Override
64     protected LocalTimeDeserializer withLeniency(Boolean leniency) {
65         return new LocalTimeDeserializer(this, leniency);
66     }
67
68     @Override
69     protected LocalTimeDeserializer withShape(JsonFormat.Shape shape) { return this; }
70
71     @Override
72     public LocalTime deserialize(JsonParser parser, DeserializationContext context) throws IOException
73     {
74         if (parser.hasToken(JsonToken.VALUE_STRING)) {
75             String string = parser.getText().trim();
76             if (string.length() == 0) {
77                 if (!isLenient()) {
78                     return _failForNotLenient(parser, context, JsonToken.VALUE_STRING);
79                 }
80                 return null;
81             }
82             DateTimeFormatter format = _formatter;
83             try {
84                 if (format == DEFAULT_FORMATTER) {
85                     if (string.contains("T")) {
86                         return LocalTime.parse(string, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
87                     }
88                 }
89                 return LocalTime.parse(string, format);
90             } catch (DateTimeException e) {
91                 return _handleDateTimeException(context, e, string);
92             }
93         }
94         if (parser.isExpectedStartArrayToken()) {
95             JsonToken t = parser.nextToken();
96             if (t == JsonToken.END_ARRAY) {
97                 return null;
98             }
99             if (context.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)
100                     && (t == JsonToken.VALUE_STRING || t==JsonToken.VALUE_EMBEDDED_OBJECT)) {
101                 final LocalTime parsed = deserialize(parser, context);
102                 if (parser.nextToken() != JsonToken.END_ARRAY) {
103                     handleMissingEndArrayForSingle(parser, context);
104                 }
105                 return parsed;            
106             }
107             if (t == JsonToken.VALUE_NUMBER_INT) {
108                 int hour = parser.getIntValue();
109     
110                 parser.nextToken();
111                 int minute = parser.getIntValue();
112                 LocalTime result;
113     
114                 t = parser.nextToken();
115                 if (t == JsonToken.END_ARRAY) {
116                     result = LocalTime.of(hour, minute);
117                 } else {
118                     int second = parser.getIntValue();
119                     t = parser.nextToken();
120                     if (t == JsonToken.END_ARRAY) {
121                         result = LocalTime.of(hour, minute, second);
122                     } else {
123                         int partialSecond = parser.getIntValue();
124                         if(partialSecond < 1_000 &&
125                                 !context.isEnabled(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS))
126                             partialSecond *= 1_000_000; // value is milliseconds, convert it to nanoseconds
127                         t = parser.nextToken();
128                         if (t != JsonToken.END_ARRAY) {
129                             throw context.wrongTokenException(parser, handledType(), JsonToken.END_ARRAY,
130                                     "Expected array to end");
131                         }
132                         result = LocalTime.of(hour, minute, second, partialSecond);
133                     }
134                 }
135                 return result;
136             }
137             context.reportInputMismatch(handledType(),
138                     "Unexpected token (%s) within Array, expected VALUE_NUMBER_INT",
139                     t);
140         }
141         if (parser.hasToken(JsonToken.VALUE_EMBEDDED_OBJECT)) {
142             return (LocalTime) parser.getEmbeddedObject();
143         }
144         if (parser.hasToken(JsonToken.VALUE_NUMBER_INT)) {
145             _throwNoNumericTimestampNeedTimeZone(parser, context);
146         }
147         return _handleUnexpectedToken(context, parser, "Expected array or string.");
148     }
149 }
150