• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

smartsheet / smartsheet-java-sdk / #55

02 Oct 2024 07:40PM UTC coverage: 60.548% (+0.7%) from 59.836%
#55

push

github

web-flow
Release prep for 3.2.1 (#103)

4156 of 6864 relevant lines covered (60.55%)

0.61 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

79.49
/src/main/java/com/smartsheet/api/internal/json/JacksonJsonSerializer.java
1
/*
2
 * Copyright (C) 2024 Smartsheet
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain 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.smartsheet.api.internal.json;
18

19
import com.fasterxml.jackson.annotation.JsonInclude.Include;
20
import com.fasterxml.jackson.core.JsonGenerationException;
21
import com.fasterxml.jackson.core.JsonParseException;
22
import com.fasterxml.jackson.core.Version;
23
import com.fasterxml.jackson.core.type.TypeReference;
24
import com.fasterxml.jackson.databind.DeserializationFeature;
25
import com.fasterxml.jackson.databind.JsonMappingException;
26
import com.fasterxml.jackson.databind.ObjectMapper;
27
import com.fasterxml.jackson.databind.SerializationFeature;
28
import com.fasterxml.jackson.databind.module.SimpleModule;
29
import com.smartsheet.api.internal.util.Util;
30
import com.smartsheet.api.models.BulkItemResult;
31
import com.smartsheet.api.models.CopyOrMoveRowResult;
32
import com.smartsheet.api.models.EventResult;
33
import com.smartsheet.api.models.Hyperlink;
34
import com.smartsheet.api.models.IdentifiableModel;
35
import com.smartsheet.api.models.IdentifiableModelMixin;
36
import com.smartsheet.api.models.ObjectValue;
37
import com.smartsheet.api.models.PagedResult;
38
import com.smartsheet.api.models.PrimitiveObjectValue;
39
import com.smartsheet.api.models.Recipient;
40
import com.smartsheet.api.models.Result;
41
import com.smartsheet.api.models.WidgetContent;
42
import com.smartsheet.api.models.format.Format;
43

44
import java.io.IOException;
45
import java.io.InputStream;
46
import java.text.SimpleDateFormat;
47
import java.util.List;
48
import java.util.Map;
49
import java.util.TimeZone;
50

51
/**
52
 * This is the Jackson based JsonSerializer implementation.
53
 * <p>
54
 * Thread Safety: This class is thread safe because it is immutable and the underlying Jackson ObjectMapper is thread
55
 * safe as long as it is not re-configured.
56
 */
57
public class JacksonJsonSerializer implements JsonSerializer {
58
    /**
59
     * Represents the ObjectMapper used to serialize/de-serialize JSON.
60
     * <p>
61
     * It will be initialized in a static initializer and will not change afterwards.
62
     * <p>
63
     * Because ObjectMapper is thread-safe as long as it's not reconfigured, a static final class-level ObjectMapper is
64
     * used to achieve best performance.
65
     */
66
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
1✔
67

68
    static {
69
        // Allow deserialization if there are properties that can't be deserialized
70
        OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
1✔
71
        OBJECT_MAPPER.configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL, true);
1✔
72

73
        // Only include non-null properties in when serializing java beans
74
        OBJECT_MAPPER.setSerializationInclusion(Include.NON_NULL);
1✔
75

76
        // Use toString() method on enums to serialize and deserialize
77
        OBJECT_MAPPER.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
1✔
78
        OBJECT_MAPPER.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
1✔
79

80
        OBJECT_MAPPER.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
1✔
81
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
1✔
82
        df.setTimeZone(TimeZone.getTimeZone("UTC"));
1✔
83
        OBJECT_MAPPER.setDateFormat(df);
1✔
84

85
        // Add a custom deserializer that will convert a string to a Format object.
86
        SimpleModule module = new SimpleModule("FormatDeserializerModule", Version.unknownVersion());
1✔
87
        module.addDeserializer(Format.class, new FormatDeserializer());
1✔
88

89
        // Add custom mixin to ignore getId() for the IdentifiableModel class
90
        module.setMixInAnnotation(IdentifiableModel.class, IdentifiableModelMixin.class);
1✔
91
        OBJECT_MAPPER.registerModule(module);
1✔
92

93
        module = new SimpleModule("ObjectValueDeserializerModule", Version.unknownVersion());
1✔
94
        module.addDeserializer(ObjectValue.class, new ObjectValueDeserializer());
1✔
95
        OBJECT_MAPPER.registerModule(module);
1✔
96

97
        module = new SimpleModule("PrimitiveObjectValueSerializerModule", Version.unknownVersion());
1✔
98
        module.addSerializer(PrimitiveObjectValue.class, new PrimitiveObjectValueSerializer());
1✔
99
        OBJECT_MAPPER.registerModule(module);
1✔
100

101
        module = new SimpleModule("RecipientDeserializerModule", Version.unknownVersion());
1✔
102
        module.addDeserializer(Recipient.class, new RecipientDeserializer());
1✔
103
        OBJECT_MAPPER.registerModule(module);
1✔
104

105
        module = new SimpleModule("WidgetContentDeserializerModule", Version.unknownVersion());
1✔
106
        module.addDeserializer(WidgetContent.class, new WidgetContentDeserializer());
1✔
107
        OBJECT_MAPPER.registerModule(module);
1✔
108

109
        module = new SimpleModule("HyperlinkSerializerModule", Version.unknownVersion());
1✔
110
        module.addSerializer(Hyperlink.class, new HyperlinkSerializer());
1✔
111
        OBJECT_MAPPER.registerModule(module);
1✔
112

113
        module = new SimpleModule("CellSerializerModule", Version.unknownVersion());
1✔
114
        module.setSerializerModifier(new CellSerializerModifier());
1✔
115
        OBJECT_MAPPER.registerModule(module);
1✔
116

117
        module = new SimpleModule("ErrorDetailDeserializerModule", Version.unknownVersion());
1✔
118
        module.addDeserializer(com.smartsheet.api.models.Error.class, new ErrorDeserializer());
1✔
119
        OBJECT_MAPPER.registerModule(module);
1✔
120
    }
1✔
121

122
    /**
123
     * Sets if the OBJECT MAPPER should ignore unknown properties or fail when de-serializing the JSON data.
124
     *
125
     * @param value true if it should fail, false otherwise.
126
     */
127
    public static void setFailOnUnknownProperties(boolean value) {
128
        OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, value);
1✔
129
    }
1✔
130

131
    /**
132
     * Constructor.
133
     * <p>
134
     * Parameters: None
135
     * <p>
136
     * Exceptions: None
137
     */
138
    public JacksonJsonSerializer() {
1✔
139
    }
1✔
140

141
    /**
142
     * Serialize an object to JSON.
143
     * <p>
144
     * Parameters:
145
     * object : the object to serialize
146
     * outputStream : the output stream to which the JSON will be written
147
     * <p>
148
     * Returns: None
149
     * <p>
150
     * Exceptions: - IllegalArgumentException : if any argument is null - JSONSerializerException : if there is any
151
     * other error occurred during the operation
152
     *
153
     * @param outputStream the output stream to write the deserialized object to
154
     * @param object       object to serialize
155
     * @throws JSONSerializerException thrown for any serialization exception we catch
156
     */
157
    // @Override
158
    public <T> void serialize(T object, java.io.OutputStream outputStream) throws JSONSerializerException {
159
        Util.throwIfNull(object, outputStream);
1✔
160

161
        try {
162
            OBJECT_MAPPER.writeValue(outputStream, object);
1✔
163
        } catch (JsonGenerationException e) {
×
164
            throw new JSONSerializerException(e);
×
165
        } catch (JsonMappingException e) {
1✔
166
            throw new JSONSerializerException(e);
1✔
167
        } catch (IOException e) {
1✔
168
            throw new JSONSerializerException(e);
1✔
169
        }
1✔
170
    }
1✔
171

172
    /**
173
     * Serialize an object to JSON.
174
     * <p>
175
     * Parameters:
176
     * object : the object to serialize
177
     * outputStream : the output stream to which the JSON will be written
178
     * <p>
179
     * Returns: None
180
     * <p>
181
     * Exceptions: - IllegalArgumentException : if any argument is null - JSONSerializerException : if there is any
182
     * other error occurred during the operation
183
     *
184
     * @param object the object to serialized
185
     * @return a string with the deserialized object
186
     * @throws JSONSerializerException thrown for any serialization exception we catch
187
     */
188
    public <T> String serialize(T object) throws JSONSerializerException {
189
        Util.throwIfNull(object);
1✔
190
        String value;
191

192
        try {
193
            value = OBJECT_MAPPER.writeValueAsString(object);
1✔
194
        } catch (JsonGenerationException e) {
×
195
            throw new JSONSerializerException(e);
×
196
        } catch (JsonMappingException e) {
×
197
            throw new JSONSerializerException(e);
×
198
        } catch (IOException e) {
×
199
            throw new JSONSerializerException(e);
×
200
        }
1✔
201
        return value;
1✔
202
    }
203

204
    /**
205
     * De-serialize an object from JSON.
206
     * <p>
207
     * Returns: the de-serialized object
208
     * <p>
209
     * Exceptions:
210
     * - IllegalArgumentException : if any argument is null
211
     * - JSONSerializerException : if there is any other error occurred during the operation
212
     *
213
     * @param inputStream the input stream from which the JSON will be read
214
     * @param objectClass the class of the object to de-serialize
215
     */
216
    // @Override
217
    public <T> T deserialize(Class<T> objectClass, java.io.InputStream inputStream) throws IOException {
218
        Util.throwIfNull(objectClass, inputStream);
1✔
219

220
        return OBJECT_MAPPER.readValue(inputStream, objectClass);
1✔
221
    }
222

223
    /**
224
     * De-serialize an object list from JSON.
225
     * <p>
226
     * Returns: the de-serialized list
227
     * <p>
228
     * Exceptions:
229
     * - IllegalArgumentException : if any argument is null
230
     * - JSONSerializerException : if there is any other error occurred during the operation
231
     *
232
     * @param inputStream the input stream from which the JSON will be read
233
     * @param objectClass the class of the object (of the list) to de-serialize
234
     */
235
    // @Override
236
    public <T> List<T> deserializeList(Class<T> objectClass, java.io.InputStream inputStream)
237
            throws JSONSerializerException {
238
        Util.throwIfNull(objectClass, inputStream);
1✔
239

240
        List<T> list = null;
1✔
241

242
        try {
243
            // Read the json input stream into a List.
244
            list = OBJECT_MAPPER.readValue(inputStream,
1✔
245
                    OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, objectClass));
1✔
246
        } catch (JsonParseException e) {
1✔
247
            throw new JSONSerializerException(e);
1✔
248
        } catch (JsonMappingException e) {
1✔
249
            throw new JSONSerializerException(e);
1✔
250
        } catch (IOException e) {
1✔
251
            throw new JSONSerializerException(e);
1✔
252
        }
1✔
253

254
        return list;
1✔
255
    }
256

257
    /**
258
     * De-serialize to a PagedResult (holds pagination info) from JSON
259
     */
260
    @Override
261
    public <T> PagedResult<T> deserializeDataWrapper(
262
            Class<T> objectClass,
263
            java.io.InputStream inputStream
264
    ) throws JSONSerializerException {
265
        Util.throwIfNull(objectClass, inputStream);
1✔
266

267
        PagedResult<T> rw = null;
1✔
268

269
        try {
270
            // Read the json input stream into a List.
271
            rw = OBJECT_MAPPER.readValue(
1✔
272
                    inputStream,
273
                    OBJECT_MAPPER
274
                            .getTypeFactory()
1✔
275
                            .constructParametrizedType(PagedResult.class, PagedResult.class, objectClass)
1✔
276
            );
277
        } catch (JsonParseException e) {
×
278
            throw new JSONSerializerException(e);
×
279
        } catch (JsonMappingException e) {
×
280
            throw new JSONSerializerException(e);
×
281
        } catch (IOException e) {
×
282
            throw new JSONSerializerException(e);
×
283
        }
1✔
284

285
        return rw;
1✔
286
    }
287

288
    /**
289
     * De-serialize to a map from JSON.
290
     */
291
    // @Override
292
    public Map<String, Object> deserializeMap(InputStream inputStream) throws JSONSerializerException {
293
        Util.throwIfNull(inputStream);
1✔
294

295
        Map<String, Object> map = null;
1✔
296

297
        try {
298
            map = OBJECT_MAPPER.readValue(inputStream, new TypeReference<Map<String, Object>>() {
1✔
299
            });
300
        } catch (JsonParseException e) {
1✔
301
            throw new JSONSerializerException(e);
1✔
302
        } catch (JsonMappingException e) {
1✔
303
            throw new JSONSerializerException(e);
1✔
304
        } catch (IOException e) {
1✔
305
            throw new JSONSerializerException(e);
1✔
306
        }
1✔
307

308
        return map;
1✔
309
    }
310

311
    /**
312
     * De-serialize a Result object from JSON.
313
     * <p>
314
     * Exceptions:
315
     * - IllegalArgumentException : if any argument is null
316
     * - JSONSerializerException : if there is any other error occurred during the operation
317
     *
318
     * @param inputStream the input stream from which the JSON will be read
319
     * @param objectClass the class of the object (of the Result) to de-serialize
320
     * @return the de-serialized result
321
     */
322
    // @Override
323
    public <T> Result<T> deserializeResult(Class<T> objectClass, java.io.InputStream inputStream)
324
            throws JSONSerializerException {
325
        Util.throwIfNull(objectClass, inputStream);
1✔
326

327
        Result<T> result = null;
1✔
328

329
        try {
330
            result = OBJECT_MAPPER.readValue(inputStream,
1✔
331
                    OBJECT_MAPPER.getTypeFactory().constructParametrizedType(Result.class, Result.class, objectClass));
1✔
332
        } catch (JsonParseException e) {
1✔
333
            throw new JSONSerializerException(e);
1✔
334
        } catch (JsonMappingException e) {
1✔
335
            throw new JSONSerializerException(e);
1✔
336
        } catch (IOException e) {
1✔
337
            throw new JSONSerializerException(e);
1✔
338
        }
1✔
339

340
        return result;
1✔
341
    }
342

343
    /**
344
     * De-serialize a List Result object from JSON.
345
     * <p>
346
     * Parameters: - objectClass :  - inputStream :
347
     * <p>
348
     * Returns: the de-serialized result
349
     * <p>
350
     * Exceptions:
351
     * - IllegalArgumentException : if any argument is null
352
     * - JSONSerializerException : if there is any other error occurred during the operation
353
     *
354
     * @param inputStream the input stream from which the JSON will be read
355
     * @param objectClass the class of the object (of the Result) to de-serialize
356
     */
357
    // @Override
358
    public <T> Result<List<T>> deserializeListResult(Class<T> objectClass, java.io.InputStream inputStream)
359
            throws JSONSerializerException {
360
        Util.throwIfNull(objectClass, inputStream);
1✔
361

362
        Result<List<T>> result = null;
1✔
363

364
        try {
365
            result = OBJECT_MAPPER.readValue(
1✔
366
                    inputStream,
367
                    OBJECT_MAPPER.getTypeFactory().constructParametrizedType(Result.class, Result.class,
1✔
368
                            OBJECT_MAPPER.getTypeFactory().constructParametrizedType(List.class, List.class, objectClass)));
1✔
369
        } catch (JsonParseException e) {
1✔
370
            throw new JSONSerializerException(e);
1✔
371
        } catch (JsonMappingException e) {
1✔
372
            throw new JSONSerializerException(e);
1✔
373
        } catch (IOException e) {
1✔
374
            throw new JSONSerializerException(e);
1✔
375
        }
1✔
376
        return result;
1✔
377
    }
378

379
    @Override
380
    public <T> BulkItemResult<T> deserializeBulkItemResult(Class<T> objectClass, InputStream inputStream)
381
            throws JSONSerializerException {
382
        BulkItemResult<T> result = null;
1✔
383
        try {
384
            result = OBJECT_MAPPER.readValue(inputStream,
1✔
385
                    OBJECT_MAPPER.getTypeFactory().constructParametrizedType(BulkItemResult.class, BulkItemResult.class, objectClass));
1✔
386
        } catch (JsonParseException e) {
×
387
            throw new JSONSerializerException(e);
×
388
        } catch (JsonMappingException e) {
×
389
            throw new JSONSerializerException(e);
×
390
        } catch (IOException e) {
×
391
            throw new JSONSerializerException(e);
×
392
        }
1✔
393
        return result;
1✔
394
    }
395

396
    /**
397
     * De-serialize to a CopyOrMoveRowResult object from JSON
398
     */
399
    @Override
400
    public CopyOrMoveRowResult deserializeCopyOrMoveRow(
401
            java.io.InputStream inputStream
402
    ) throws JSONSerializerException {
403
        Util.throwIfNull(inputStream);
1✔
404

405
        CopyOrMoveRowResult rw = null;
1✔
406

407
        try {
408
            // Read the json input stream into a List.
409
            rw = OBJECT_MAPPER.readValue(inputStream, CopyOrMoveRowResult.class);
1✔
410
        } catch (JsonParseException e) {
×
411
            throw new JSONSerializerException(e);
×
412
        } catch (JsonMappingException e) {
×
413
            throw new JSONSerializerException(e);
×
414
        } catch (IOException e) {
×
415
            throw new JSONSerializerException(e);
×
416
        }
1✔
417

418
        return rw;
1✔
419
    }
420

421
    /**
422
     * De-serialize to a EventResult (holds pagination info) from JSON
423
     */
424
    @Override
425
    public EventResult deserializeEventResult(java.io.InputStream inputStream) throws JSONSerializerException {
426
        Util.throwIfNull(inputStream);
1✔
427

428
        EventResult rw = null;
1✔
429

430
        try {
431
            // Read the json input stream into a List.
432
            rw = OBJECT_MAPPER.readValue(inputStream, EventResult.class);
1✔
433
        } catch (JsonParseException e) {
×
434
            throw new JSONSerializerException(e);
×
435
        } catch (JsonMappingException e) {
×
436
            throw new JSONSerializerException(e);
×
437
        } catch (IOException e) {
×
438
            throw new JSONSerializerException(e);
×
439
        }
1✔
440

441
        return rw;
1✔
442
    }
443
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc