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

smartsheet / smartsheet-java-sdk / #58

23 Sep 2025 06:13PM UTC coverage: 59.737% (-1.1%) from 60.803%
#58

push

github

web-flow
Add user downgrade seat type endpoint (#131)

* Add support for upgrade user seat type route

* Change return type

* Add support for the user downgrade seat type endpoint

* Remove * imports, replace switch with if statement, remove overload

* Update changelog and build.gradle

* Add user downgrade and upgrade API calls

* Add user downgrade and upgrade API calls

* Add user downgrade and upgrade API calls

* Add user downgrade and upgrade API calls

---------

Co-authored-by: Velihan Zelev <velihan.zelev@smartsheet.com>

12 of 13 new or added lines in 2 files covered. (92.31%)

192 existing lines in 7 files now uncovered.

4310 of 7215 relevant lines covered (59.74%)

0.6 hits per line

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

72.09
/src/main/java/com/smartsheet/api/internal/json/JacksonJsonSerializer.java
1
/*
2
 * Copyright (C) 2025 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.JsonDeserializer;
26
import com.fasterxml.jackson.databind.JsonMappingException;
27
import com.fasterxml.jackson.databind.ObjectMapper;
28
import com.fasterxml.jackson.databind.SerializationFeature;
29
import com.fasterxml.jackson.databind.module.SimpleModule;
30
import com.smartsheet.api.internal.util.Util;
31
import com.smartsheet.api.models.BulkItemResult;
32
import com.smartsheet.api.models.CopyOrMoveRowResult;
33
import com.smartsheet.api.models.EventResult;
34
import com.smartsheet.api.models.Hyperlink;
35
import com.smartsheet.api.models.IdentifiableModel;
36
import com.smartsheet.api.models.IdentifiableModelMixin;
37
import com.smartsheet.api.models.ObjectValue;
38
import com.smartsheet.api.models.PagedResult;
39
import com.smartsheet.api.models.PrimitiveObjectValue;
40
import com.smartsheet.api.models.Recipient;
41
import com.smartsheet.api.models.Result;
42
import com.smartsheet.api.models.TokenPaginatedResult;
43
import com.smartsheet.api.models.WidgetContent;
44
import com.smartsheet.api.models.format.Format;
45

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

222
        return OBJECT_MAPPER.readValue(inputStream, objectClass);
1✔
223
    }
224

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

242
        List<T> list = null;
1✔
243

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

256
        return list;
1✔
257
    }
258

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

269
        PagedResult<T> rw = null;
1✔
270

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

287
        return rw;
1✔
288
    }
289

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

297
        Map<String, Object> map = null;
1✔
298

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

310
        return map;
1✔
311
    }
312

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

329
        Result<T> result = null;
1✔
330

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

342
        return result;
1✔
343
    }
344

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

364
        Result<List<T>> result = null;
1✔
365

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

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

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

407
        CopyOrMoveRowResult rw = null;
1✔
408

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

420
        return rw;
1✔
421
    }
422

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

430
        EventResult rw = null;
1✔
431

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

443
        return rw;
1✔
444
    }
445

446
    /**
447
     * De-serialize json to TokenPaginatedResult using a custom deserializer.
448
     *
449
     * @param <T> the generic type of the data items
450
     * @param deserializer the custom deserializer for the data items
451
     * @param inputStream the input stream
452
     * @return the TokenPaginatedResult containing a list of type T
453
     * @throws JSONSerializerException the JSON serializer exception
454
     */
455
    @Override
456
    public <T> TokenPaginatedResult<T> deserializeTokenPaginatedResult(JsonDeserializer<List<T>> deserializer, InputStream inputStream)
457
            throws JSONSerializerException {
UNCOV
458
        Util.throwIfNull(deserializer, inputStream);
×
459

UNCOV
460
        TokenPaginatedResult<T> result = null;
×
461

462
        try {
463
            // Create a temporary ObjectMapper with the custom deserializer
UNCOV
464
            ObjectMapper tempMapper = OBJECT_MAPPER.copy();
×
UNCOV
465
            SimpleModule module = new SimpleModule("TokenPaginatedResultDeserializerModule", Version.unknownVersion());
×
UNCOV
466
            module.addDeserializer(List.class, deserializer);
×
UNCOV
467
            tempMapper.registerModule(module);
×
468

469
            // Deserialize using the temporary mapper with custom deserializer
UNCOV
470
            result = tempMapper.readValue(inputStream,
×
UNCOV
471
                    tempMapper.getTypeFactory().constructParametrizedType(TokenPaginatedResult.class,
×
472
                            TokenPaginatedResult.class, Object.class));
UNCOV
473
        } catch (JsonParseException e) {
×
UNCOV
474
            throw new JSONSerializerException(e);
×
UNCOV
475
        } catch (JsonMappingException e) {
×
UNCOV
476
            throw new JSONSerializerException(e);
×
UNCOV
477
        } catch (IOException e) {
×
UNCOV
478
            throw new JSONSerializerException(e);
×
UNCOV
479
        }
×
480

UNCOV
481
        return result;
×
482
    }
483
}
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