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 com.fasterxml.jackson.annotation.JsonFormat;
20 import com.fasterxml.jackson.core.JsonParser;
21 import com.fasterxml.jackson.core.JsonToken;
22 import com.fasterxml.jackson.core.JsonTokenId;
23 import com.fasterxml.jackson.databind.BeanProperty;
24 import com.fasterxml.jackson.databind.DeserializationContext;
25 import com.fasterxml.jackson.databind.DeserializationFeature;
26 import com.fasterxml.jackson.databind.JsonDeserializer;
27 import com.fasterxml.jackson.databind.JsonMappingException;
28 import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
29 import com.fasterxml.jackson.datatype.jsr310.DecimalUtils;
30
31 import java.io.IOException;
32 import java.math.BigDecimal;
33 import java.time.DateTimeException;
34 import java.time.Duration;
35
36
37 /**
38  * Deserializer for Java 8 temporal {@link Duration}s.
39  *
40  * @author Nick Williams
41  * @since 2.2.0
42  */

43 public class DurationDeserializer extends JSR310DeserializerBase<Duration> implements ContextualDeserializer
44 {
45     private static final long serialVersionUID = 1L;
46
47     public static final DurationDeserializer INSTANCE = new DurationDeserializer();
48
49     private DurationDeserializer()
50     {
51         super(Duration.class);
52     }
53
54     /**
55      * Since 2.11
56      */

57     protected DurationDeserializer(DurationDeserializer base, Boolean leniency) {
58         super(base, leniency);
59     }
60
61     @Override
62     protected DurationDeserializer withLeniency(Boolean leniency) {
63         return new DurationDeserializer(this, leniency);
64     }
65
66     @Override
67     public Duration deserialize(JsonParser parser, DeserializationContext context) throws IOException
68     {
69         switch (parser.getCurrentTokenId())
70         {
71             case JsonTokenId.ID_NUMBER_FLOAT:
72                 BigDecimal value = parser.getDecimalValue();
73                 return DecimalUtils.extractSecondsAndNanos(value, Duration::ofSeconds);
74
75             case JsonTokenId.ID_NUMBER_INT:
76                 if(context.isEnabled(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS)) {
77                     return Duration.ofSeconds(parser.getLongValue());
78                 }
79                 return Duration.ofMillis(parser.getLongValue());
80
81             case JsonTokenId.ID_STRING:
82                 String string = parser.getText().trim();
83                 if (string.length() == 0) {
84                     if (!isLenient()) {
85                         return _failForNotLenient(parser, context, JsonToken.VALUE_STRING);
86                     }
87                     return null;
88                 }
89                 try {
90                     return Duration.parse(string);
91                 } catch (DateTimeException e) {
92                     return _handleDateTimeException(context, e, string);
93                 }
94             case JsonTokenId.ID_EMBEDDED_OBJECT:
95                 // 20-Apr-2016, tatu: Related to [databind#1208], can try supporting embedded
96                 //    values quite easily
97                 return (Duration) parser.getEmbeddedObject();
98                 
99             case JsonTokenId.ID_START_ARRAY:
100                 return _deserializeFromArray(parser, context);
101         }
102         return _handleUnexpectedToken(context, parser, JsonToken.VALUE_STRING,
103                 JsonToken.VALUE_NUMBER_INT, JsonToken.VALUE_NUMBER_FLOAT);
104     }
105
106     @Override
107     public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
108                                                 BeanProperty property) throws JsonMappingException
109     {
110         JsonFormat.Value format = findFormatOverrides(ctxt, property, handledType());
111         DurationDeserializer deser = this;
112         if (format != null) {
113             if (format.hasLenient()) {
114                 Boolean leniency = format.getLenient();
115                 if (leniency != null) {
116                     deser = deser.withLeniency(leniency);
117                 }
118             }
119         }
120         return deser;
121     }
122 }
123