21
21
import com .fasterxml .jackson .core .JsonParser ;
22
22
import com .fasterxml .jackson .core .JsonToken ;
23
23
24
+ import com .fasterxml .jackson .databind .BeanProperty ;
24
25
import com .fasterxml .jackson .databind .JavaType ;
25
26
import com .fasterxml .jackson .databind .JsonMappingException ;
27
+ import com .fasterxml .jackson .databind .JsonSerializer ;
26
28
import com .fasterxml .jackson .databind .SerializationFeature ;
27
29
import com .fasterxml .jackson .databind .SerializerProvider ;
28
30
import com .fasterxml .jackson .databind .jsonFormatVisitors .JsonFormatVisitorWrapper ;
29
31
import com .fasterxml .jackson .databind .jsonFormatVisitors .JsonIntegerFormatVisitor ;
30
32
import com .fasterxml .jackson .databind .jsonFormatVisitors .JsonValueFormat ;
31
33
import com .fasterxml .jackson .datatype .jsr310 .DecimalUtils ;
34
+ import com .fasterxml .jackson .datatype .jsr310 .util .DurationUnitConverter ;
32
35
33
36
import java .io .IOException ;
34
37
import java .math .BigDecimal ;
@@ -52,6 +55,16 @@ public class DurationSerializer extends JSR310FormattedSerializerBase<Duration>
52
55
53
56
public static final DurationSerializer INSTANCE = new DurationSerializer ();
54
57
58
+ /**
59
+ * When defined (not {@code null}) duration values will be converted into integers
60
+ * with the unit configured for the converter.
61
+ * Only available when {@link SerializationFeature#WRITE_DURATIONS_AS_TIMESTAMPS} is enabled
62
+ * and {@link SerializationFeature#WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS} is not enabled
63
+ * since the duration converters do not support fractions
64
+ * @since 2.12
65
+ */
66
+ private DurationUnitConverter _durationUnitConverter ;
67
+
55
68
private DurationSerializer () {
56
69
super (Duration .class );
57
70
}
@@ -66,45 +79,80 @@ protected DurationSerializer(DurationSerializer base,
66
79
super (base , useTimestamp , useNanoseconds , dtf , null );
67
80
}
68
81
82
+ protected DurationSerializer (DurationSerializer base , DurationUnitConverter converter ) {
83
+ super (base , base ._useTimestamp , base ._useNanoseconds , base ._formatter , base ._shape );
84
+ _durationUnitConverter = converter ;
85
+ }
86
+
69
87
@ Override
70
88
protected DurationSerializer withFormat (Boolean useTimestamp , DateTimeFormatter dtf , JsonFormat .Shape shape ) {
71
89
return new DurationSerializer (this , useTimestamp , dtf );
72
90
}
73
91
92
+ protected DurationSerializer withConverter (DurationUnitConverter converter ) {
93
+ return new DurationSerializer (this , converter );
94
+ }
95
+
74
96
// @since 2.10
75
97
@ Override
76
98
protected SerializationFeature getTimestampsFeature () {
77
99
return SerializationFeature .WRITE_DURATIONS_AS_TIMESTAMPS ;
78
100
}
79
101
102
+ @ Override
103
+ public JsonSerializer <?> createContextual (SerializerProvider prov , BeanProperty property ) throws JsonMappingException {
104
+ DurationSerializer ser = (DurationSerializer ) super .createContextual (prov , property );
105
+ JsonFormat .Value format = findFormatOverrides (prov , property , handledType ());
106
+ if (format != null && format .hasPattern ()) {
107
+ final String pattern = format .getPattern ();
108
+ DurationUnitConverter p = DurationUnitConverter .from (pattern );
109
+ if (p == null ) {
110
+ prov .reportBadDefinition (handledType (),
111
+ String .format (
112
+ "Bad 'pattern' definition (\" %s\" ) for `Duration`: expected one of [%s]" ,
113
+ pattern , DurationUnitConverter .descForAllowed ()));
114
+ }
115
+
116
+ ser = ser .withConverter (p );
117
+ }
118
+ return ser ;
119
+ }
120
+
80
121
@ Override
81
122
public void serialize (Duration duration , JsonGenerator generator , SerializerProvider provider ) throws IOException
82
123
{
83
124
if (useTimestamp (provider )) {
84
125
if (useNanoseconds (provider )) {
85
- // 20-Oct-2020, tatu: [modules-java8#165] Need to take care of
86
- // negative values too, and without work-around values
87
- // returned are wonky wrt conversions
88
- BigDecimal bd ;
89
- if (duration .isNegative ()) {
90
- duration = duration .abs ();
91
- bd = DecimalUtils .toBigDecimal (duration .getSeconds (),
92
- duration .getNano ())
93
- .negate ();
126
+ generator .writeNumber (_toNanos (duration ));
127
+ } else {
128
+ if (_durationUnitConverter != null ) {
129
+ generator .writeNumber (_durationUnitConverter .convert (duration ));
94
130
} else {
95
- bd = DecimalUtils .toBigDecimal (duration .getSeconds (),
96
- duration .getNano ());
131
+ generator .writeNumber (duration .toMillis ());
97
132
}
98
- generator .writeNumber (bd );
99
- } else {
100
- generator .writeNumber (duration .toMillis ());
101
133
}
102
134
} else {
103
- // Does not look like we can make any use of DateTimeFormatter here?
104
135
generator .writeString (duration .toString ());
105
136
}
106
137
}
107
138
139
+ // 20-Oct-2020, tatu: [modules-java8#165] Need to take care of
140
+ // negative values too, and without work-around values
141
+ // returned are wonky wrt conversions
142
+ private BigDecimal _toNanos (Duration duration ) {
143
+ BigDecimal bd ;
144
+ if (duration .isNegative ()) {
145
+ duration = duration .abs ();
146
+ bd = DecimalUtils .toBigDecimal (duration .getSeconds (),
147
+ duration .getNano ())
148
+ .negate ();
149
+ } else {
150
+ bd = DecimalUtils .toBigDecimal (duration .getSeconds (),
151
+ duration .getNano ());
152
+ }
153
+ return bd ;
154
+ }
155
+
108
156
@ Override
109
157
protected void _acceptTimestampVisitor (JsonFormatVisitorWrapper visitor , JavaType typeHint ) throws JsonMappingException
110
158
{
@@ -135,4 +183,9 @@ protected JsonToken serializationShape(SerializerProvider provider) {
135
183
protected JSR310FormattedSerializerBase <?> withFeatures (Boolean writeZoneId , Boolean writeNanoseconds ) {
136
184
return new DurationSerializer (this , _useTimestamp , writeNanoseconds , _formatter );
137
185
}
186
+
187
+ @ Override
188
+ protected DateTimeFormatter _useDateTimeFormatter (SerializerProvider prov , JsonFormat .Value format ) {
189
+ return null ;
190
+ }
138
191
}
0 commit comments