-
-
Notifications
You must be signed in to change notification settings - Fork 8.7k
Expand file tree
/
Copy pathJson.java
More file actions
243 lines (227 loc) · 10.8 KB
/
Copy pathJson.java
File metadata and controls
243 lines (227 loc) · 10.8 KB
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
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.openqa.selenium.json;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.UncheckedIOException;
import java.io.Writer;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import org.jspecify.annotations.Nullable;
import org.openqa.selenium.internal.Require;
/**
* The <b>Json</b> class is the entrypoint for the JSON processing features of the Selenium API.
* These features include:
*
* <ul>
* <li>Built-in JSON deserialization to primitives and collections from the standard types shown
* below.
* <li>Facilities to deserialize JSON to custom data types:
* <ul>
* <li>Classes that declare a {@code fromJson(T)} static method, where <b>T</b> is any of
* the standard types shown below.
* <li>Classes that declare a {@code fromJson(JsonInput)} static method.<br>
* <b>NOTE</b>: Objects deserialized via a {@code fromJson} static method can be
* immutable.
* <li>Classes that declare a constructor whose parameter names are available at runtime.
* <br>
* <b>NOTE</b>: Constructor parameter names are only available if they are present in
* the class file, such as when the class is compiled with {@code javac -parameters}.
* Constructor parameter names must match the corresponding JSON field names. Parameters
* of type {@link java.util.Optional Optional} are not required.
* <li>Classes that declare setter methods adhering to the <a
* href="https://docs.oracle.com/javase/tutorial/javabeans/writing/index.html">JavaBean</a>
* specification.<br>
* <b>NOTE</b>: Deserialized {@code JavaBean} objects are mutable, which may be
* undesirable.
* </ul>
* <li>Built-in JSON serialization from primitives and collections from the standard types shown
* below.
* <li>Facilities to serialize custom data types to JSON:
* <ul>
* <li>Classes that declare a {@code toJson()} method returning a primitive or collection
* from the standard types shown below.
* <li>Classes that declare getter methods adhering to the {@code JavaBean} specification.
* </ul>
* </ul>
*
* The standard types supported by built-in processing:
*
* <ul>
* <li><b>Numeric Types</b>:<br>
* {@link java.lang.Byte Byte}, {@link java.lang.Double Double}, {@link java.lang.Float
* Float}, {@link java.lang.Integer Integer}, {@link java.lang.Long Long}, {@link
* java.lang.Short Short}
* <li><b>Collection Types</b>:<br>
* {@link java.util.Collection Collection}, {@link java.util.List List}, {@link java.util.Set
* Set}
* <li><b>Standard Java Types</b>:<br>
* {@link java.util.Map Map}, {@link java.lang.Boolean Boolean}, {@link java.lang.String
* String}, {@link java.lang.Enum Enum}, {@link java.net.URI URI}, {@link java.net.URL URL},
* {@link java.util.UUID UUID}, {@link java.time.Instant Instant}, {@link java.util.Optional
* Optional}, {@link java.lang.Object Object}
* </ul>
*
* You can serialize objects for which no explicit coercer has been specified, and the <b>Json</b>
* API will use a generic process to provide best-effort JSON output. For the most predictable
* results, though, it's best to provide a {@code toJson()} method for the <b>Json</b> API to use
* for serialization. This is especially beneficial for objects that contain transient properties
* that should be omitted from the JSON output.
*
* <p>You can deserialize objects for which no explicit handling has been defined. Note that the
* data type of the result will be {@code Map<String,?>}, which means that you'll need to perform
* type checking and casting every time you extract an entry value from the result. For this reason,
* it's best to declare either a type-specific {@code fromJson()} method or a constructor with
* runtime-visible parameter names in every type you need to deserialize.
*
* @see JsonTypeCoercer
* @see JsonInput
* @see JsonOutput
*/
public class Json {
/**
* The value of {@code Content-Type} headers for HTTP requests and responses with JSON entities
*/
public static final String JSON_UTF_8 = "application/json; charset=utf-8";
/** Specifier for {@code List<Map<String, Object>} input/output type */
public static final Type LIST_OF_MAPS_TYPE =
new TypeToken<List<Map<String, Object>>>() {}.getType();
/** Specifier for {@code Map<String, Object>} input/output type */
public static final Type MAP_TYPE = new TypeToken<Map<String, Object>>() {}.getType();
/** Specifier for {@code Object} input/output type */
public static final Type OBJECT_TYPE = new TypeToken<Object>() {}.getType();
private final JsonTypeCoercer fromJson = new JsonTypeCoercer();
/**
* Serialize the specified object to JSON string representation.<br>
* <b>NOTE</b>: This method limits traversal of nested objects to the default {@link
* JsonOutput#MAX_DEPTH maximum depth}.
*
* @param toConvert the object to be serialized
* @return JSON string representing the specified object
*/
public String toJson(@Nullable Object toConvert) {
return toJson(toConvert, JsonOutput.MAX_DEPTH);
}
/**
* Serialize the specified object to JSON string representation.
*
* @param toConvert the object to be serialized
* @param maxDepth maximum depth of nested object traversal
* @return JSON string representing the specified object
* @throws JsonException if an I/O exception is encountered
*/
public String toJson(@Nullable Object toConvert, int maxDepth) {
try (Writer writer = new StringWriter();
JsonOutput jsonOutput = newOutput(writer)) {
jsonOutput.write(toConvert, maxDepth);
return writer.toString();
} catch (IOException e) {
throw new JsonException("Cannot convert " + toConvert + " to json", e);
}
}
/**
* Deserialize the specified JSON string into an object of the specified type.<br>
* <b>NOTE</b>: This method uses the {@link PropertySetting#BY_NAME BY_NAME} strategy to assign
* values to properties in the deserialized object.
*
* @param source serialized source as JSON string
* @param typeOfT data type for deserialization (class or {@link TypeToken})
* @return object of the specified type deserialized from [source]
* @param <T> result type (as specified by [typeOfT])
* @throws JsonException if an I/O exception is encountered
*/
public <T> T toType(String source, Type typeOfT) {
return toType(source, typeOfT, PropertySetting.BY_NAME);
}
/**
* Deserialize the specified JSON string into an object of the specified type.
*
* @param source serialized source as JSON string
* @param typeOfT data type for deserialization (class or {@link TypeToken})
* @param setter strategy used to assign values during deserialization
* @return object of the specified type deserialized from [source]
* @param <T> result type (as specified by [typeOfT])
* @throws JsonException if an I/O exception is encountered
*/
public <T> T toType(String source, Type typeOfT, PropertySetting setter) {
try (StringReader reader = new StringReader(source)) {
return toType(reader, typeOfT, setter);
} catch (JsonException e) {
throw new JsonException("Unable to parse: " + source, e);
}
}
/**
* Deserialize the JSON string supplied by the specified {@code Reader} into an object of the
* specified type.<br>
* <b>NOTE</b>: This method uses the {@link PropertySetting#BY_NAME BY_NAME} strategy to assign
* values to properties in the deserialized object.
*
* @param source {@link Reader} that supplies a serialized JSON string
* @param typeOfT data type for deserialization (class or {@link TypeToken})
* @return object of the specified type deserialized from [source]
* @param <T> result type (as specified by [typeOfT])
* @throws JsonException if an I/O exception is encountered
*/
public <T> T toType(Reader source, Type typeOfT) {
return toType(source, typeOfT, PropertySetting.BY_NAME);
}
/**
* Deserialize the JSON string supplied by the specified {@code Reader} into an object of the
* specified type.
*
* @param source {@link Reader} that supplies a serialized JSON string
* @param typeOfT data type for deserialization (class or {@link TypeToken})
* @param setter strategy used to assign values during deserialization
* @return object of the specified type deserialized from [source]
* @param <T> result type (as specified by [typeOfT])
* @throws JsonException if an I/O exception is encountered
*/
public <T> T toType(Reader source, Type typeOfT, PropertySetting setter) {
Require.nonNull("Mechanism for setting properties", setter);
try (JsonInput json = newInput(source)) {
return fromJson.coerce(json, typeOfT, setter);
}
}
/**
* Create a new {@code JsonInput} object to traverse the JSON string supplied the specified {@code
* Reader}.<br>
* <b>NOTE</b>: The {@code JsonInput} object returned by this method uses the {@link
* PropertySetting#BY_NAME BY_NAME} strategy to assign values to properties objects it
* deserializes.
*
* @param from {@link Reader} that supplies a serialized JSON string
* @return {@link JsonInput} object to traverse the JSON string supplied by [from]
* @throws UncheckedIOException if an I/O exception occurs
*/
public JsonInput newInput(Reader from) throws UncheckedIOException {
return new JsonInput(from, fromJson, PropertySetting.BY_NAME);
}
/**
* Create a new {@code JsonOutput} object to produce a serialized JSON string in the specified
* {@code Appendable}.
*
* @param to {@link Appendable} that consumes a serialized JSON string
* @return {@link JsonOutput} object to product a JSON string in [to]
* @throws UncheckedIOException if an I/O exception occurs
*/
public JsonOutput newOutput(Appendable to) throws UncheckedIOException {
return new JsonOutput(to);
}
}