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.ser;
18
19 import java.io.IOException;
20 import java.time.LocalTime;
21 import java.time.format.DateTimeFormatter;
22 import java.time.temporal.ChronoField;
23
24 import com.fasterxml.jackson.annotation.JsonFormat;
25 import com.fasterxml.jackson.core.JsonGenerator;
26 import com.fasterxml.jackson.core.JsonToken;
27 import com.fasterxml.jackson.core.type.WritableTypeId;
28 import com.fasterxml.jackson.databind.JavaType;
29 import com.fasterxml.jackson.databind.JsonMappingException;
30 import com.fasterxml.jackson.databind.SerializerProvider;
31 import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
32 import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonStringFormatVisitor;
33 import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonValueFormat;
34 import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
35 /**
36  * Serializer for Java 8 temporal {@link LocalTime}s.
37  *
38  * @author Nick Williams
39  * @since 2.2
40  */

41 public class LocalTimeSerializer extends JSR310FormattedSerializerBase<LocalTime>
42 {
43     private static final long serialVersionUID = 1L;
44
45     public static final LocalTimeSerializer INSTANCE = new LocalTimeSerializer();
46
47     protected LocalTimeSerializer() {
48         this(null);
49     }
50
51     public LocalTimeSerializer(DateTimeFormatter formatter) {
52         super(LocalTime.class, formatter);
53     }
54
55     protected LocalTimeSerializer(LocalTimeSerializer base, Boolean useTimestamp, DateTimeFormatter formatter) {
56         this(base, useTimestamp, null, formatter);
57     }
58
59     protected LocalTimeSerializer(LocalTimeSerializer base, Boolean useTimestamp, Boolean useNanoseconds, DateTimeFormatter formatter) {
60         super(base, useTimestamp, useNanoseconds, formatter, null);
61     }
62
63     @Override
64     protected JSR310FormattedSerializerBase<LocalTime> withFormat(Boolean useTimestamp, DateTimeFormatter dtf, JsonFormat.Shape shape) {
65         return new LocalTimeSerializer(this, useTimestamp, dtf);
66     }
67
68     // since 2.7: TODO in 2.8; change to use per-type defaulting
69     protected DateTimeFormatter _defaultFormatter() {
70         return DateTimeFormatter.ISO_LOCAL_TIME;
71     }
72
73     @Override
74     public void serialize(LocalTime value, JsonGenerator g, SerializerProvider provider)
75         throws IOException
76     {
77         if (useTimestamp(provider)) {
78             g.writeStartArray();
79             _serializeAsArrayContents(value, g, provider);
80             g.writeEndArray();
81         } else {
82             DateTimeFormatter dtf = _formatter;
83             if (dtf == null) {
84                 dtf = _defaultFormatter();
85             }
86             g.writeString(value.format(dtf));
87         }
88     }
89
90     @Override
91     public void serializeWithType(LocalTime value, JsonGenerator g,
92             SerializerProvider provider, TypeSerializer typeSer) throws IOException
93     {
94         WritableTypeId typeIdDef = typeSer.writeTypePrefix(g,
95                 typeSer.typeId(value, serializationShape(provider)));
96         // need to write out to avoid double-writing array markers
97         if (typeIdDef.valueShape == JsonToken.START_ARRAY) {
98             _serializeAsArrayContents(value, g, provider);
99         } else {
100             DateTimeFormatter dtf = _formatter;
101             if (dtf == null) {
102                 dtf = _defaultFormatter();
103             }
104             g.writeString(value.format(dtf));
105         }
106         typeSer.writeTypeSuffix(g, typeIdDef);
107     }
108
109     private final void _serializeAsArrayContents(LocalTime value, JsonGenerator g,
110             SerializerProvider provider) throws IOException
111     {
112         g.writeNumber(value.getHour());
113         g.writeNumber(value.getMinute());
114         int secs = value.getSecond();
115         int nanos = value.getNano();
116         if ((secs > 0) || (nanos > 0))
117         {
118             g.writeNumber(secs);
119             if (nanos > 0) {
120                 if (useNanoseconds(provider)) {
121                     g.writeNumber(nanos);
122                 } else {
123                     g.writeNumber(value.get(ChronoField.MILLI_OF_SECOND));
124                 }
125             }
126         }
127     }
128
129     @Override // since 2.9
130     protected JsonToken serializationShape(SerializerProvider provider) {
131         return useTimestamp(provider) ? JsonToken.START_ARRAY : JsonToken.VALUE_STRING;
132     }
133
134     @Override
135     protected JSR310FormattedSerializerBase<?> withFeatures(Boolean writeZoneId, Boolean writeNanoseconds) {
136         return new LocalTimeSerializer(this, _useTimestamp, writeNanoseconds, _formatter);
137     }
138
139     // as per [modules-java8#105]
140     @Override
141     public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType typeHint)
142         throws JsonMappingException
143     {
144         if (useTimestamp(visitor.getProvider())) {
145             _acceptTimestampVisitor(visitor, typeHint);
146         } else {
147             JsonStringFormatVisitor v2 = visitor.expectStringFormat(typeHint);
148             if (v2 != null) {
149                 v2.format(JsonValueFormat.TIME);
150             }
151         }
152     }
153 }
154