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 package gov.nist.secauto.metaschema.core.model.util;
28
29 import com.fasterxml.jackson.core.JsonLocation;
30 import com.fasterxml.jackson.core.JsonParser;
31 import com.fasterxml.jackson.core.JsonToken;
32
33 import gov.nist.secauto.metaschema.core.util.CustomCollectors;
34 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
35
36 import org.apache.logging.log4j.LogManager;
37 import org.apache.logging.log4j.Logger;
38 import org.json.JSONObject;
39 import org.json.JSONTokener;
40
41 import java.io.IOException;
42 import java.io.InputStream;
43 import java.io.Reader;
44 import java.util.Arrays;
45 import java.util.Collection;
46 import java.util.List;
47
48 import edu.umd.cs.findbugs.annotations.NonNull;
49 import edu.umd.cs.findbugs.annotations.Nullable;
50
51 public final class JsonUtil {
52 private static final Logger LOGGER = LogManager.getLogger(JsonUtil.class);
53
54 private JsonUtil() {
55
56 }
57
58 @NonNull
59 public static JSONObject toJsonObject(@NonNull InputStream schemaInputStream) {
60 return new JSONObject(new JSONTokener(schemaInputStream));
61 }
62
63 @NonNull
64 public static JSONObject toJsonObject(@NonNull Reader reader) {
65 return new JSONObject(new JSONTokener(reader));
66 }
67
68
69
70
71
72
73
74
75
76
77
78 @SuppressWarnings("null")
79 @NonNull
80 public static String toString(@NonNull JsonParser parser) throws IOException {
81 return new StringBuilder(32)
82 .append(parser.currentToken().name())
83 .append(" '")
84 .append(parser.getText())
85 .append('\'')
86 .append(generateLocationMessage(parser))
87 .toString();
88 }
89
90
91
92
93
94
95
96
97 @SuppressWarnings("null")
98 @NonNull
99 public static String toString(@NonNull JsonLocation location) {
100 return new StringBuilder(8)
101 .append(location.getLineNr())
102 .append(':')
103 .append(location.getColumnNr())
104 .toString();
105 }
106
107 @Nullable
108 public static JsonToken advanceTo(@NonNull JsonParser parser, JsonToken token) throws IOException {
109 JsonToken currentToken = null;
110 while (parser.hasCurrentToken() && !token.equals(currentToken = parser.currentToken())) {
111 currentToken = parser.nextToken();
112 if (LOGGER.isWarnEnabled()) {
113 LOGGER.warn("skipping over: {}{}",
114 toString(parser),
115 generateLocationMessage(parser));
116 }
117 }
118 return currentToken;
119 }
120
121 @SuppressWarnings({
122 "resource",
123 "PMD.CyclomaticComplexity"
124 })
125 @Nullable
126 public static JsonToken skipNextValue(@NonNull JsonParser parser) throws IOException {
127
128 JsonToken currentToken = parser.currentToken();
129
130 if (JsonToken.FIELD_NAME.equals(currentToken)) {
131 currentToken = parser.nextToken();
132 }
133
134 switch (currentToken) {
135 case START_ARRAY:
136 case START_OBJECT:
137 parser.skipChildren();
138 break;
139 case VALUE_FALSE:
140 case VALUE_NULL:
141 case VALUE_NUMBER_FLOAT:
142 case VALUE_NUMBER_INT:
143 case VALUE_STRING:
144 case VALUE_TRUE:
145
146 break;
147 default:
148
149 String msg = String.format("Unhandled JsonToken %s%s.",
150 toString(parser),
151 generateLocationMessage(parser));
152 LOGGER.error(msg);
153 throw new UnsupportedOperationException(msg);
154 }
155
156
157 return parser.nextToken();
158 }
159
160 @SuppressWarnings("PMD.CyclomaticComplexity")
161 public static boolean checkEndOfValue(@NonNull JsonParser parser, @NonNull JsonToken startToken) {
162 JsonToken currentToken = parser.getCurrentToken();
163
164 boolean retval;
165 switch (startToken) {
166 case START_OBJECT:
167 retval = JsonToken.END_OBJECT.equals(currentToken);
168 break;
169 case START_ARRAY:
170 retval = JsonToken.END_ARRAY.equals(currentToken);
171 break;
172 case VALUE_EMBEDDED_OBJECT:
173 case VALUE_FALSE:
174 case VALUE_NULL:
175 case VALUE_NUMBER_FLOAT:
176 case VALUE_NUMBER_INT:
177 case VALUE_STRING:
178 case VALUE_TRUE:
179 retval = true;
180 break;
181 default:
182 retval = false;
183 }
184 return retval;
185 }
186
187 public static void assertCurrent(
188 @NonNull JsonParser parser,
189 @NonNull JsonToken... expectedTokens) {
190 JsonToken current = parser.currentToken();
191 assert Arrays.stream(expectedTokens)
192 .anyMatch(expected -> expected.equals(current)) : getAssertMessage(
193 parser,
194 expectedTokens,
195 parser.currentToken());
196 }
197
198 public static void assertCurrentIsFieldValue(@NonNull JsonParser parser) {
199 JsonToken token = parser.currentToken();
200 assert token.isStructStart() || token.isScalarValue() : String.format(
201 "Expected a START_OBJECT, START_ARRAY, or VALUE_xxx token, but found JsonToken '%s'%s.",
202 token,
203 generateLocationMessage(parser));
204 }
205
206 @Nullable
207 public static JsonToken assertAndAdvance(
208 @NonNull JsonParser parser,
209 @NonNull JsonToken expectedToken)
210 throws IOException {
211 JsonToken token = parser.currentToken();
212 assert expectedToken.equals(token) : getAssertMessage(
213 parser,
214 expectedToken,
215 token);
216 return parser.nextToken();
217 }
218
219 @Nullable
220 public static JsonToken advanceAndAssert(
221 @NonNull JsonParser parser,
222 @NonNull JsonToken expectedToken)
223 throws IOException {
224 JsonToken token = parser.nextToken();
225 assert expectedToken.equals(token) : getAssertMessage(
226 parser,
227 expectedToken,
228 token);
229 return token;
230 }
231
232 @NonNull
233 public static String getAssertMessage(
234 @NonNull JsonParser parser,
235 @NonNull JsonToken expected,
236 JsonToken actual) {
237 return ObjectUtils.notNull(
238 String.format("Expected JsonToken '%s', but found JsonToken '%s'%s.",
239 expected,
240 actual,
241 generateLocationMessage(parser)));
242 }
243
244 @NonNull
245 public static String getAssertMessage(
246 @NonNull JsonParser parser,
247 @NonNull JsonToken[] expected,
248 JsonToken actual) {
249 List<JsonToken> expectedTokens = ObjectUtils.notNull(Arrays.asList(expected));
250 return getAssertMessage(parser, expectedTokens, actual);
251 }
252
253 @NonNull
254 public static String getAssertMessage(
255 @NonNull JsonParser parser,
256 @NonNull Collection<JsonToken> expected,
257 JsonToken actual) {
258 return ObjectUtils.notNull(
259 String.format("Expected JsonToken(s) '%s', but found JsonToken '%s'%s.",
260 expected.stream().map(token -> token.name()).collect(CustomCollectors.joiningWithOxfordComma("and")),
261 actual,
262 generateLocationMessage(parser)));
263 }
264
265 @NonNull
266 public static CharSequence generateLocationMessage(@NonNull JsonParser parser) {
267 JsonLocation location = parser.getCurrentLocation();
268 return location == null ? "" : generateLocationMessage(location);
269 }
270
271 @SuppressWarnings("null")
272 @NonNull
273 public static CharSequence generateLocationMessage(@NonNull JsonLocation location) {
274 return new StringBuilder()
275 .append(" at location '")
276 .append(location.getLineNr())
277 .append(':')
278 .append(location.getColumnNr())
279 .append('\'');
280 }
281 }