@@ -43,6 +43,12 @@ public class StreamReadConstraints
43
43
*/
44
44
public static final long DEFAULT_MAX_DOC_LEN = -1L ;
45
45
46
+ /**
47
+ * Default setting for maximum token count:
48
+ * see {@link Builder#maxTokenCount} for details.
49
+ */
50
+ public static final long DEFAULT_MAX_TOKEN_COUNT = -1L ;
51
+
46
52
/**
47
53
* @since 2.16
48
54
*/
@@ -74,6 +80,7 @@ public class StreamReadConstraints
74
80
75
81
protected final int _maxNestingDepth ;
76
82
protected final long _maxDocLen ;
83
+ protected final long _maxTokenCount ;
77
84
78
85
protected final int _maxNumLen ;
79
86
protected final int _maxStringLen ;
@@ -112,6 +119,7 @@ public static void overrideDefaultStreamReadConstraints(final StreamReadConstrai
112
119
113
120
public static final class Builder {
114
121
private long maxDocLen ;
122
+ private long maxTokenCount ;
115
123
private int maxNestingDepth ;
116
124
private int maxNumLen ;
117
125
private int maxStringLen ;
@@ -156,6 +164,31 @@ public Builder maxDocumentLength(long maxDocLen) {
156
164
return this ;
157
165
}
158
166
167
+ /**
168
+ * Sets the maximum allowed token count (for positive values over 0) or
169
+ * indicate that any count is acceptable ({@code 0} or negative number).
170
+ *
171
+ * <p>
172
+ * A token is a single unit of input, such as a number, a string, an object
173
+ * start or end, or an array start or end.
174
+ * </p>
175
+ *
176
+ * @param maxTokenCount the maximum allowed token count if positive number above 0; otherwise
177
+ * ({@code 0} or negative number) means "unlimited".
178
+ *
179
+ * @return this builder
180
+ *
181
+ * @since 2.18
182
+ */
183
+ public Builder maxTokenCount (long maxTokenCount ) {
184
+ // Negative values and 0 mean "unlimited", mark with -1L
185
+ if (maxTokenCount <= 0L ) {
186
+ maxTokenCount = -1L ;
187
+ }
188
+ this .maxTokenCount = maxTokenCount ;
189
+ return this ;
190
+ }
191
+
159
192
/**
160
193
* Sets the maximum number length (in chars or bytes, depending on input context).
161
194
* The default is 1000.
@@ -220,14 +253,15 @@ public Builder maxNameLength(final int maxNameLen) {
220
253
}
221
254
222
255
Builder () {
223
- this (DEFAULT_MAX_DEPTH , DEFAULT_MAX_DOC_LEN ,
256
+ this (DEFAULT_MAX_DEPTH , DEFAULT_MAX_DOC_LEN , DEFAULT_MAX_TOKEN_COUNT ,
224
257
DEFAULT_MAX_NUM_LEN , DEFAULT_MAX_STRING_LEN , DEFAULT_MAX_NAME_LEN );
225
258
}
226
259
227
- Builder (final int maxNestingDepth , final long maxDocLen ,
260
+ Builder (final int maxNestingDepth , final long maxDocLen , final long maxTokenCount ,
228
261
final int maxNumLen , final int maxStringLen , final int maxNameLen ) {
229
262
this .maxNestingDepth = maxNestingDepth ;
230
263
this .maxDocLen = maxDocLen ;
264
+ this .maxTokenCount = maxTokenCount ;
231
265
this .maxNumLen = maxNumLen ;
232
266
this .maxStringLen = maxStringLen ;
233
267
this .maxNameLen = maxNameLen ;
@@ -236,14 +270,15 @@ public Builder maxNameLength(final int maxNameLen) {
236
270
Builder (StreamReadConstraints src ) {
237
271
maxNestingDepth = src ._maxNestingDepth ;
238
272
maxDocLen = src ._maxDocLen ;
273
+ maxTokenCount = src ._maxTokenCount ;
239
274
maxNumLen = src ._maxNumLen ;
240
275
maxStringLen = src ._maxStringLen ;
241
276
maxNameLen = src ._maxNameLen ;
242
277
}
243
278
244
279
public StreamReadConstraints build () {
245
280
return new StreamReadConstraints (maxNestingDepth , maxDocLen ,
246
- maxNumLen , maxStringLen , maxNameLen );
281
+ maxNumLen , maxStringLen , maxNameLen , maxTokenCount );
247
282
}
248
283
}
249
284
@@ -257,7 +292,7 @@ public StreamReadConstraints build() {
257
292
protected StreamReadConstraints (final int maxNestingDepth , final long maxDocLen ,
258
293
final int maxNumLen , final int maxStringLen ) {
259
294
this (maxNestingDepth , maxDocLen ,
260
- maxNumLen , maxStringLen , DEFAULT_MAX_NAME_LEN );
295
+ maxNumLen , maxStringLen , DEFAULT_MAX_NAME_LEN , DEFAULT_MAX_TOKEN_COUNT );
261
296
}
262
297
263
298
/**
@@ -269,13 +304,30 @@ protected StreamReadConstraints(final int maxNestingDepth, final long maxDocLen,
269
304
*
270
305
* @since 2.16
271
306
*/
307
+ @ Deprecated // since 2.18
308
+ protected StreamReadConstraints (final int maxNestingDepth , final long maxDocLen ,
309
+ final int maxNumLen , final int maxStringLen , final int maxNameLen ) {
310
+ this (maxNestingDepth , maxDocLen , maxNumLen , maxStringLen , maxNameLen , DEFAULT_MAX_TOKEN_COUNT );
311
+ }
312
+
313
+ /**
314
+ * @param maxNestingDepth Maximum input document nesting to allow
315
+ * @param maxDocLen Maximum input document length to allow
316
+ * @param maxNumLen Maximum number representation length to allow
317
+ * @param maxStringLen Maximum String value length to allow
318
+ * @param maxNameLen Maximum Object property name length to allow
319
+ * @param maxTokenCount Maximum number of tokens to allow
320
+ *
321
+ * @since 2.18
322
+ */
272
323
protected StreamReadConstraints (final int maxNestingDepth , final long maxDocLen ,
273
- final int maxNumLen , final int maxStringLen , final int maxNameLen ) {
324
+ final int maxNumLen , final int maxStringLen , final int maxNameLen , final long maxTokenCount ) {
274
325
_maxNestingDepth = maxNestingDepth ;
275
326
_maxDocLen = maxDocLen ;
276
327
_maxNumLen = maxNumLen ;
277
328
_maxStringLen = maxStringLen ;
278
329
_maxNameLen = maxNameLen ;
330
+ _maxTokenCount = maxTokenCount ;
279
331
}
280
332
281
333
public static Builder builder () {
@@ -337,6 +389,31 @@ public boolean hasMaxDocumentLength() {
337
389
return _maxDocLen > 0L ;
338
390
}
339
391
392
+ /**
393
+ * Accessor for maximum token count.
394
+ * see {@link Builder#maxTokenCount(long)} for details.
395
+ *
396
+ * @return Maximum allowed token count
397
+ * @since 2.18
398
+ */
399
+ public long getMaxTokenCount () {
400
+ return _maxTokenCount ;
401
+ }
402
+
403
+ /**
404
+ * Convenience method, basically same as:
405
+ *<pre>
406
+ * getMaxTokenCount() > 0L
407
+ *</pre>
408
+ *
409
+ * @return {@code True} if this constraints instance has a limit for maximum
410
+ * token count to enforce; {@code false} otherwise.
411
+ * @since 2.18
412
+ */
413
+ public boolean hasMaxTokenCount () {
414
+ return _maxTokenCount > 0L ;
415
+ }
416
+
340
417
/**
341
418
* Accessor for maximum length of numbers to decode.
342
419
* see {@link Builder#maxNumberLength(int)} for details.
@@ -419,6 +496,31 @@ public void validateDocumentLength(long len) throws StreamConstraintsException
419
496
}
420
497
}
421
498
499
+ /**
500
+ * Convenience method that can be used to verify that the
501
+ * token count does not exceed the maximum specified by this
502
+ * constraints object (if any): if it does, a
503
+ * {@link StreamConstraintsException}
504
+ * is thrown.
505
+ *
506
+ * @param count Current token count for processed document content
507
+ *
508
+ * @throws StreamConstraintsException If length exceeds maximum
509
+ *
510
+ * @since 2.18
511
+ */
512
+ public void validateTokenCount (long count ) throws StreamConstraintsException
513
+ {
514
+ // for performance reasons, it is assumed that users check hasMaxTokenCount()
515
+ // before calling this method - this method will not work properly if hasMaxTokenCount() is false
516
+ if (count > _maxTokenCount ) {
517
+ throw _constructException (
518
+ "Token count (%d) exceeds the maximum allowed (%d, from %s)" ,
519
+ count , _maxTokenCount ,
520
+ _constrainRef ("getMaxTokenCount" ));
521
+ }
522
+ }
523
+
422
524
/*
423
525
/**********************************************************************
424
526
/* Convenience methods for validation, token lengths
0 commit comments