forked from gitlab4j/gitlab4j-api
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathJacksonJson.java
370 lines (325 loc) · 15.5 KB
/
JacksonJson.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
package org.gitlab4j.models.utils;
import java.io.IOException;
import java.io.Reader;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import org.gitlab4j.api.models.User;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.type.CollectionType;
/**
* Jackson JSON Configuration and utility class.
*/
public class JacksonJson {
private static final SimpleDateFormat iso8601UtcFormat;
static {
iso8601UtcFormat = new SimpleDateFormat(ISO8601.UTC_PATTERN);
iso8601UtcFormat.setLenient(true);
iso8601UtcFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
}
private final ObjectMapper objectMapper;
public JacksonJson() {
objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(Include.NON_NULL);
objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
objectMapper.configure(SerializationFeature.WRITE_ENUMS_USING_TO_STRING, true);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure(DeserializationFeature.READ_ENUMS_USING_TO_STRING, true);
SimpleModule module = new SimpleModule("GitLabApiJsonModule");
module.addSerializer(Date.class, new JsonDateSerializer());
module.addDeserializer(Date.class, new JsonDateDeserializer());
objectMapper.registerModule(module);
}
/**
* Gets the ObjectMapper contained by this instance.
*
* @return the ObjectMapper contained by this instance
*/
public ObjectMapper getObjectMapper() {
return (objectMapper);
}
/**
* Reads and parses the String containing JSON data and returns a JsonNode tree representation.
*
* @param postData a String holding the POST data
* @return a JsonNode instance containing the parsed JSON
* @throws JsonParseException when an error occurs parsing the provided JSON
* @throws JsonMappingException if a JSON error occurs
* @throws IOException if an error occurs reading the JSON data
*/
public JsonNode readTree(String postData) throws JsonParseException, JsonMappingException, IOException {
return (objectMapper.readTree(postData));
}
/**
* Reads and parses the JSON data on the specified Reader instance to a JsonNode tree representation.
*
* @param reader the Reader instance that contains the JSON data
* @return a JsonNode instance containing the parsed JSON
* @throws JsonParseException when an error occurs parsing the provided JSON
* @throws JsonMappingException if a JSON error occurs
* @throws IOException if an error occurs reading the JSON data
*/
public JsonNode readTree(Reader reader) throws JsonParseException, JsonMappingException, IOException {
return (objectMapper.readTree(reader));
}
/**
* Unmarshal the JsonNode (tree) to an instance of the provided class.
*
* @param <T> the generics type for the return value
* @param returnType an instance of this type class will be returned
* @param tree the JsonNode instance that contains the JSON data
* @return an instance of the provided class containing the data from the tree
* @throws JsonParseException when an error occurs parsing the provided JSON
* @throws JsonMappingException if a JSON error occurs
* @throws IOException if an error occurs reading the JSON data
*/
public <T> T unmarshal(Class<T> returnType, JsonNode tree)
throws JsonParseException, JsonMappingException, IOException {
return (objectMapper.treeToValue(tree, returnType));
}
/**
* Unmarshal the JSON data on the specified Reader instance to an instance of the provided class.
*
* @param <T> the generics type for the return value
* @param returnType an instance of this type class will be returned
* @param reader the Reader instance that contains the JSON data
* @return an instance of the provided class containing the parsed data from the Reader
* @throws JsonParseException when an error occurs parsing the provided JSON
* @throws JsonMappingException if a JSON error occurs
* @throws IOException if an error occurs reading the JSON data
*/
public <T> T unmarshal(Class<T> returnType, Reader reader)
throws JsonParseException, JsonMappingException, IOException {
return (objectMapper.readValue(reader, returnType));
}
/**
* Unmarshal the JSON data contained by the string and populate an instance of the provided returnType class.
*
* @param <T> the generics type for the return value
* @param returnType an instance of this type class will be returned
* @param postData a String holding the POST data
* @return an instance of the provided class containing the parsed data from the string
* @throws JsonParseException when an error occurs parsing the provided JSON
* @throws JsonMappingException if a JSON error occurs
* @throws IOException if an error occurs reading the JSON data
*/
public <T> T unmarshal(Class<T> returnType, String postData)
throws JsonParseException, JsonMappingException, IOException {
return (objectMapper.readValue(postData, returnType));
}
/**
* Unmarshal the JSON data on the specified Reader instance and populate a List of instances of the provided returnType class.
*
* @param <T> the generics type for the List
* @param returnType an instance of this type class will be contained in the returned List
* @param reader the Reader instance that contains the JSON data
* @return a List of the provided class containing the parsed data from the Reader
* @throws JsonParseException when an error occurs parsing the provided JSON
* @throws JsonMappingException if a JSON error occurs
* @throws IOException if an error occurs reading the JSON data
*/
public <T> List<T> unmarshalList(Class<T> returnType, Reader reader)
throws JsonParseException, JsonMappingException, IOException {
CollectionType javaType = objectMapper.getTypeFactory().constructCollectionType(List.class, returnType);
return (objectMapper.readValue(reader, javaType));
}
/**
* Unmarshal the JSON data contained by the string and populate a List of instances of the provided returnType class.
*
* @param <T> the generics type for the List
* @param returnType an instance of this type class will be contained in the returned List
* @param postData a String holding the POST data
* @return a List of the provided class containing the parsed data from the string
* @throws JsonParseException when an error occurs parsing the provided JSON
* @throws JsonMappingException if a JSON error occurs
* @throws IOException if an error occurs reading the JSON data
*/
public <T> List<T> unmarshalList(Class<T> returnType, String postData)
throws JsonParseException, JsonMappingException, IOException {
CollectionType javaType = objectMapper.getTypeFactory().constructCollectionType(List.class, returnType);
return (objectMapper.readValue(postData, javaType));
}
/**
* Unmarshal the JSON data on the specified Reader instance and populate a Map of String keys and values of the provided returnType class.
*
* @param <T> the generics type for the Map value
* @param returnType an instance of this type class will be contained the values of the Map
* @param reader the Reader instance that contains the JSON data
* @return a Map containing the parsed data from the Reader
* @throws JsonParseException when an error occurs parsing the provided JSON
* @throws JsonMappingException if a JSON error occurs
* @throws IOException if an error occurs reading the JSON data
*/
public <T> Map<String, T> unmarshalMap(Class<T> returnType, Reader reader)
throws JsonParseException, JsonMappingException, IOException {
return (objectMapper.readValue(reader, new TypeReference<Map<String, T>>() {}));
}
/**
* Unmarshal the JSON data and populate a Map of String keys and values of the provided returnType class.
*
* @param <T> the generics type for the Map value
* @param returnType an instance of this type class will be contained the values of the Map
* @param jsonData the String containing the JSON data
* @return a Map containing the parsed data from the String
* @throws JsonParseException when an error occurs parsing the provided JSON
* @throws JsonMappingException if a JSON error occurs
* @throws IOException if an error occurs reading the JSON data
*/
public <T> Map<String, T> unmarshalMap(Class<T> returnType, String jsonData)
throws JsonParseException, JsonMappingException, IOException {
return (objectMapper.readValue(jsonData, new TypeReference<Map<String, T>>() {}));
}
/**
* Marshals the supplied object out as a formatted JSON string.
*
* @param <T> the generics type for the provided object
* @param object the object to output as a JSON string
* @return a String containing the JSON for the specified object
*/
public <T> String marshal(final T object) {
if (object == null) {
throw new IllegalArgumentException("object parameter is null");
}
ObjectWriter writer = objectMapper.writer().withDefaultPrettyPrinter();
String results = null;
try {
results = writer.writeValueAsString(object);
} catch (JsonGenerationException e) {
System.err.println("JsonGenerationException, message=" + e.getMessage());
} catch (JsonMappingException e) {
e.printStackTrace();
System.err.println("JsonMappingException, message=" + e.getMessage());
} catch (IOException e) {
System.err.println("IOException, message=" + e.getMessage());
}
return (results);
}
/**
* JsonSerializer for serializing dates s yyyy-mm-dd in UTC timezone.
*/
public static class DateOnlySerializer extends JsonSerializer<Date> {
@Override
public void serialize(Date date, JsonGenerator gen, SerializerProvider provider)
throws IOException, JsonProcessingException {
String dateString = ISO8601.dateOnly(date);
gen.writeString(dateString);
}
}
/**
* JsonSerializer for serializing ISO8601 formatted dates.
*/
public static class JsonDateSerializer extends JsonSerializer<Date> {
@Override
public void serialize(Date date, JsonGenerator gen, SerializerProvider provider)
throws IOException, JsonProcessingException {
String iso8601String = ISO8601.toString(date);
gen.writeString(iso8601String);
}
}
/**
* JsonDeserializer for deserializing ISO8601 formatted dates.
*/
public static class JsonDateDeserializer extends JsonDeserializer<Date> {
@Override
public Date deserialize(JsonParser jsonparser, DeserializationContext context)
throws IOException, JsonProcessingException {
try {
return (ISO8601.toDate(jsonparser.getText()));
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}
/**
* Serializer for the odd User instances in the "approved_by" array in the merge_request JSON.
*/
public static class UserListSerializer extends JsonSerializer<List<User>> {
@Override
public void serialize(List<User> value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonProcessingException {
jgen.writeStartArray();
for (User user : value) {
jgen.writeStartObject();
jgen.writeObjectField("user", user);
jgen.writeEndObject();
}
jgen.writeEndArray();
}
}
/**
* Deserializer for the odd User instances in the "approved_by" array in the merge_request JSON.
*/
public static class UserListDeserializer extends JsonDeserializer<List<User>> {
private static final ObjectMapper mapper = new JacksonJson().getObjectMapper();
@Override
public List<User> deserialize(JsonParser jsonParser, DeserializationContext context)
throws IOException, JsonProcessingException {
JsonNode tree = jsonParser.readValueAsTree();
int numUsers = tree.size();
List<User> users = new ArrayList<>(numUsers);
for (int i = 0; i < numUsers; i++) {
JsonNode node = tree.get(i);
JsonNode userNode = node.get("user");
User user = mapper.treeToValue(userNode, User.class);
users.add(user);
}
return (users);
}
}
/**
* This class is used to create a thread-safe singleton instance of JacksonJson customized
* to be used by
*/
private static class JacksonJsonSingletonHelper {
private static final JacksonJson JACKSON_JSON = new JacksonJson();
static {
JACKSON_JSON.objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.LOWER_CAMEL_CASE);
JACKSON_JSON.objectMapper.setSerializationInclusion(Include.ALWAYS);
}
}
/**
* Gets a the supplied object output as a formatted JSON string. Null properties will
* result in the value of the property being null. This is meant to be used for
* toString() implementations of GitLab4J classes.
*
* @param <T> the generics type for the provided object
* @param object the object to output as a JSON string
* @return a String containing the JSON for the specified object
*/
public static <T> String toJsonString(final T object) {
return (JacksonJsonSingletonHelper.JACKSON_JSON.marshal(object));
}
/**
* Parse the provided String into a JsonNode instance.
*
* @param jsonString a String containing JSON to parse
* @return a JsonNode with the String parsed into a JSON tree
* @throws IOException if any IO error occurs
*/
public static JsonNode toJsonNode(String jsonString) throws IOException {
return (JacksonJsonSingletonHelper.JACKSON_JSON.objectMapper.readTree(jsonString));
}
}