4646import org .openqa .selenium .internal .Require ;
4747import org .openqa .selenium .logging .LogLevelMapping ;
4848
49- /** */
49+ /**
50+ * The <b>JsonOutput</b> class defines the operations used to serialize Java objects into JSON
51+ * strings.
52+ */
5053public class JsonOutput implements Closeable {
5154 private static final Logger LOG = Logger .getLogger (JsonOutput .class .getName ());
5255 static final int MAX_DEPTH = 100 ;
@@ -123,9 +126,9 @@ public class JsonOutput implements Closeable {
123126 };
124127
125128 this .stack = new ArrayDeque <>();
126- this .stack .addFirst (new Empty ());
129+ this .stack .addFirst (new Root ());
127130
128- // Order matters, since we want to handle null values first to avoid exceptions, and then then
131+ // Order matters, since we want to handle null values first to avoid exceptions, and then the
129132 // common kinds of inputs next.
130133 Map <Predicate <Class <?>>, DepthAwareConsumer > builder = new LinkedHashMap <>();
131134 builder .put (Objects ::isNull , (obj , maxDepth , depthRemaining ) -> append ("null" ));
@@ -261,8 +264,12 @@ public class JsonOutput implements Closeable {
261264 }
262265
263266 /**
264- * @param enablePrettyPrinting
265- * @return
267+ * Specify whether the serialized JSON object should br formatted with line breaks and indention
268+ * ("pretty printed").
269+ *
270+ * @param enablePrettyPrinting {@code false} for compact format; {@code true} for "pretty
271+ * printing" (default: {@code true})
272+ * @return this {@link JsonOutput} object
266273 */
267274 public JsonOutput setPrettyPrint (boolean enablePrettyPrinting ) {
268275 this .lineSeparator = enablePrettyPrinting ? "\n " : "" ;
@@ -271,16 +278,21 @@ public JsonOutput setPrettyPrint(boolean enablePrettyPrinting) {
271278 }
272279
273280 /**
274- * @param writeClassName
275- * @return
281+ * Specify whether the serialized JSON object should include a "class" property whose value is the
282+ * fully-qualified class name of the Java object being serialized.
283+ *
284+ * @param writeClassName Whether to include the "class" property (default: {@code true})
285+ * @return this {@link JsonOutput} object
276286 */
277287 public JsonOutput writeClassName (boolean writeClassName ) {
278288 this .writeClassName = writeClassName ;
279289 return this ;
280290 }
281291
282292 /**
283- * @return
293+ * Begin a new JSON object.
294+ *
295+ * @return this {@link JsonOutput} object
284296 */
285297 public JsonOutput beginObject () {
286298 stack .getFirst ().write ("{" + lineSeparator );
@@ -290,8 +302,12 @@ public JsonOutput beginObject() {
290302 }
291303
292304 /**
293- * @param name
294- * @return
305+ * Set the name of a new JSON object property.
306+ *
307+ * @param name JSON object property name
308+ * @return this {@link JsonOutput} object
309+ * @throws JsonException if top item on serialization object stack isn't a {@link JsonObject}
310+ * @throws java.util.NoSuchElementException if serialization object stack is empty
295311 */
296312 public JsonOutput name (String name ) {
297313 if (!(stack .getFirst () instanceof JsonObject )) {
@@ -302,7 +318,11 @@ public JsonOutput name(String name) {
302318 }
303319
304320 /**
305- * @return
321+ * End the current JSON object.
322+ *
323+ * @return this {@link JsonOutput} object
324+ * @throws JsonException if top item on serialization object stack isn't a {@link JsonObject}
325+ * @throws java.util.NoSuchElementException if serialization object stack is empty
306326 */
307327 public JsonOutput endObject () {
308328 Node topOfStack = stack .getFirst ();
@@ -321,7 +341,9 @@ public JsonOutput endObject() {
321341 }
322342
323343 /**
324- * @return
344+ * Begin a new JSON array.
345+ *
346+ * @return this {@link JsonOutput} object
325347 */
326348 public JsonOutput beginArray () {
327349 append ("[" + lineSeparator );
@@ -331,7 +353,11 @@ public JsonOutput beginArray() {
331353 }
332354
333355 /**
334- * @return
356+ * End the current JSON array.
357+ *
358+ * @return this {@link JsonOutput} object
359+ * @throws JsonException if top item on serialization object stack isn't a {@link JsonCollection}
360+ * @throws java.util.NoSuchElementException if serialization object stack is empty
335361 */
336362 public JsonOutput endArray () {
337363 Node topOfStack = stack .getFirst ();
@@ -350,28 +376,30 @@ public JsonOutput endArray() {
350376 }
351377
352378 /**
353- * @param value
354- * @return
379+ * Serialize the specified Java object as a JSON value.<br>
380+ * <b>NOTE</b>: This method limits traversal of nested objects to the default {@link #MAX_DEPTH
381+ * maximum depth}.
382+ *
383+ * @param value Java object to serialize
384+ * @return this {@link JsonOutput} object
385+ * @throws JsonException if allowed depth has been reached
355386 */
356387 public JsonOutput write (Object value ) {
357388 return write (value , MAX_DEPTH );
358389 }
359390
360391 /**
361- * @param value
362- * @param maxDepth
363- * @return
392+ * Serialize the specified Java object as a JSON value.
393+ *
394+ * @param value Java object to serialize
395+ * @param maxDepth maximum depth of nested object traversal
396+ * @return this {@link JsonOutput} object
397+ * @throws JsonException if allowed depth has been reached
364398 */
365399 public JsonOutput write (Object value , int maxDepth ) {
366400 return write0 (value , maxDepth , maxDepth );
367401 }
368402
369- /**
370- * @param input
371- * @param maxDepth
372- * @param depthRemaining
373- * @return
374- */
375403 private JsonOutput write0 (Object input , int maxDepth , int depthRemaining ) {
376404 converters .entrySet ().stream ()
377405 .filter (entry -> entry .getKey ().test (input == null ? null : input .getClass ()))
@@ -387,6 +415,7 @@ private JsonOutput write0(Object input, int maxDepth, int depthRemaining) {
387415 * {@inheritDoc}
388416 *
389417 * @throws JsonException if JSON stream isn't empty or an I/O exception is encountered
418+ * @throws java.util.NoSuchElementException if serialization object stack is empty
390419 */
391420 @ Override
392421 public void close () {
@@ -398,23 +427,21 @@ public void close() {
398427 }
399428 }
400429
401- if (!(stack .getFirst () instanceof Empty )) {
430+ if (!(stack .getFirst () instanceof Root )) {
402431 throw new JsonException ("Attempting to close incomplete json stream" );
403432 }
404433 }
405434
406- /**
407- * @param text
408- * @return
409- */
410435 private JsonOutput append (String text ) {
411436 stack .getFirst ().write (text );
412437 return this ;
413438 }
414439
415440 /**
416- * @param obj
417- * @return
441+ * Return a quoted JSON string representing the specified Java object.
442+ *
443+ * @param obj Java object to be represented
444+ * @return quoted JSON string
418445 */
419446 private String asString (Object obj ) {
420447 StringBuilder toReturn = new StringBuilder ("\" " );
@@ -437,9 +464,13 @@ private String asString(Object obj) {
437464 }
438465
439466 /**
440- * @param clazz
441- * @param methodName
442- * @return
467+ * Get a reference to a method of the specified name with no argument in the indicated class or
468+ * one of its ancestors.
469+ *
470+ * @param clazz target Java class
471+ * @param methodName method name
472+ * @return {@link Method} object with 'accessible' flag set
473+ * @throws JsonException if a security violation is encountered
443474 */
444475 private Method getMethod (Class <?> clazz , String methodName ) {
445476 if (Object .class .equals (clazz )) {
@@ -459,11 +490,20 @@ private Method getMethod(Class<?> clazz, String methodName) {
459490 }
460491
461492 /**
462- * @param methodName
463- * @param toConvert
464- * @param maxDepth
465- * @param depthRemaining
466- * @return
493+ * Convert the specified Java object using the indicated zero-argument method of this object.
494+ *
495+ * @param methodName method name
496+ * @param toConvert Java object to be converted
497+ * @param maxDepth maximum depth of nested object traversal
498+ * @param depthRemaining allowed traversal depth remaining
499+ * @return this {@link JsonOutput} object
500+ * @throws JsonException
501+ * <ul>
502+ * <li>if the specified method isn't found
503+ * <li>if a security violation is encountered
504+ * <li>if a reflective operation fails
505+ * <li>if maximum traversal depth is exceeded
506+ * </ul>
467507 */
468508 private JsonOutput convertUsingMethod (
469509 String methodName , Object toConvert , int maxDepth , int depthRemaining ) {
@@ -482,9 +522,13 @@ private JsonOutput convertUsingMethod(
482522 }
483523
484524 /**
485- * @param toConvert
486- * @param maxDepth
487- * @param depthRemaining
525+ * Convert the specified Java object via accessors that conform to the {@code JavaBean}
526+ * specification.
527+ *
528+ * @param toConvert Java object to be converted
529+ * @param maxDepth maximum depth of nested object traversal
530+ * @param depthRemaining allowed traversal depth remaining
531+ * @throws JsonException if allowed depth has been reached
488532 */
489533 private void mapObject (Object toConvert , int maxDepth , int depthRemaining ) {
490534 if (toConvert instanceof Class ) {
@@ -516,12 +560,17 @@ private void mapObject(Object toConvert, int maxDepth, int depthRemaining) {
516560 endObject ();
517561 }
518562
519- /** */
520- private class Node {
563+ /** Defines to common behavior of JSON containers (objects and arrays). */
564+ private abstract class Node {
521565 protected boolean isEmpty = true ;
522566
523567 /**
524- * @param text
568+ * Write the specified text to the appender of this JSON output object.<br>
569+ * <b>NOTE</b>: If prior text has been written to this container, the new text is prefixed with
570+ * a comma and the defined line separator (either {@literal <newline>} or empty string) to
571+ * delimit a new object property or array item.
572+ *
573+ * @param text text to be appended to the output
525574 */
526575 public void write (String text ) {
527576 if (isEmpty ) {
@@ -535,9 +584,15 @@ public void write(String text) {
535584 }
536585 }
537586
538- /** */
539- private class Empty extends Node {
587+ /** Represents the root of the JSON output. */
588+ private class Root extends Node {
540589
590+ /**
591+ * Write the specified text to the appender of this JSON output object.
592+ *
593+ * @param text text to be appended to the output
594+ * @throws JsonException if this {@link JsonOutput} has already been used.
595+ */
541596 @ Override
542597 public void write (String text ) {
543598 if (!isEmpty ) {
@@ -548,15 +603,19 @@ public void write(String text) {
548603 }
549604 }
550605
551- /** */
606+ /** Represents a JSON array. */
552607 private class JsonCollection extends Node {}
553608
554- /** */
609+ /** Represents a JSON object. */
555610 private class JsonObject extends Node {
556611 private boolean isNameNext = true ;
557612
558613 /**
559- * @param name
614+ * Writes the name of a JSON property followed by a colon to the appender of this JSON output
615+ * object.
616+ *
617+ * @param name JSON object property name
618+ * @throws JsonException if not expecting a new JSON property
560619 */
561620 public void name (String name ) {
562621 if (!isNameNext ) {
@@ -567,6 +626,12 @@ public void name(String name) {
567626 appender .accept (": " );
568627 }
569628
629+ /**
630+ * Write the value of a JSON property to the appender of this JSON output object.
631+ *
632+ * @param text JSON object property value
633+ * @throws JsonException if not expecting a JSON property value
634+ */
570635 @ Override
571636 public void write (String text ) {
572637 if (isNameNext ) {
@@ -578,14 +643,19 @@ public void write(String text) {
578643 }
579644 }
580645
581- /** */
646+ /**
647+ * Defines the common interface for the Java object traversal serializers of {@link JsonOutput}.
648+ */
582649 @ FunctionalInterface
583650 private interface DepthAwareConsumer {
584651
585652 /**
586- * @param object
587- * @param maxDepth
588- * @param depthRemaining
653+ * Consume the specified Java object, emitting its JSON representation to the appender of this
654+ * {@link JsonOutput}.
655+ *
656+ * @param object Java object to be serialized
657+ * @param maxDepth maximum depth of nested object traversal
658+ * @param depthRemaining allowed traversal depth remaining
589659 */
590660 void consume (Object object , int maxDepth , int depthRemaining );
591661 }
0 commit comments