Skip to content

Commit

Permalink
Finish up JavaDoc for the 'Json' classes (#12609)
Browse files Browse the repository at this point in the history
* Add JavaDoc to 'Json' classes

* Format file

---------

Co-authored-by: Diego Molina <diemol@users.noreply.github.com>
Co-authored-by: Diego Molina <diemol@gmail.com>
  • Loading branch information
3 people committed Aug 28, 2023
1 parent e08916a commit 327785f
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 84 deletions.
10 changes: 0 additions & 10 deletions java/src/org/openqa/selenium/json/JsonInput.java
Expand Up @@ -46,16 +46,6 @@ public class JsonInput implements Closeable {
// figuring out whether we're expecting a NAME properly.
private final Deque<Container> stack = new ArrayDeque<>();

/**
* This package-private constructor initializes new instances of the {@code JsonInput} class.<br>
* This class declares methods that enable structured traversal of the JSON string supplied by the
* {@code Reader} object specified by [source].
*
* @param source {@link Reader} object that supplies the JSON string to be processed
* @param coercer {@link JsonTypeCoercer} that encapsulates the defined type-specific
* deserializers
* @param setter strategy used to assign values during deserialization
*/
JsonInput(Reader source, JsonTypeCoercer coercer, PropertySetting setter) {
this.source = Require.nonNull("Source", source);
this.coercer = Require.nonNull("Coercer", coercer);
Expand Down
178 changes: 124 additions & 54 deletions java/src/org/openqa/selenium/json/JsonOutput.java
Expand Up @@ -46,7 +46,10 @@
import org.openqa.selenium.internal.Require;
import org.openqa.selenium.logging.LogLevelMapping;

/** */
/**
* The <b>JsonOutput</b> class defines the operations used to serialize Java objects into JSON
* strings.
*/
public class JsonOutput implements Closeable {
private static final Logger LOG = Logger.getLogger(JsonOutput.class.getName());
static final int MAX_DEPTH = 100;
Expand Down Expand Up @@ -123,9 +126,9 @@ public class JsonOutput implements Closeable {
};

this.stack = new ArrayDeque<>();
this.stack.addFirst(new Empty());
this.stack.addFirst(new Root());

// Order matters, since we want to handle null values first to avoid exceptions, and then then
// Order matters, since we want to handle null values first to avoid exceptions, and then the
// common kinds of inputs next.
Map<Predicate<Class<?>>, DepthAwareConsumer> builder = new LinkedHashMap<>();
builder.put(Objects::isNull, (obj, maxDepth, depthRemaining) -> append("null"));
Expand Down Expand Up @@ -261,8 +264,12 @@ public class JsonOutput implements Closeable {
}

/**
* @param enablePrettyPrinting
* @return
* Specify whether the serialized JSON object should br formatted with line breaks and indention
* ("pretty printed").
*
* @param enablePrettyPrinting {@code false} for compact format; {@code true} for "pretty
* printing" (default: {@code true})
* @return this {@link JsonOutput} object
*/
public JsonOutput setPrettyPrint(boolean enablePrettyPrinting) {
this.lineSeparator = enablePrettyPrinting ? "\n" : "";
Expand All @@ -271,16 +278,21 @@ public JsonOutput setPrettyPrint(boolean enablePrettyPrinting) {
}

/**
* @param writeClassName
* @return
* Specify whether the serialized JSON object should include a "class" property whose value is the
* fully-qualified class name of the Java object being serialized.
*
* @param writeClassName Whether to include the "class" property (default: {@code true})
* @return this {@link JsonOutput} object
*/
public JsonOutput writeClassName(boolean writeClassName) {
this.writeClassName = writeClassName;
return this;
}

/**
* @return
* Begin a new JSON object.
*
* @return this {@link JsonOutput} object
*/
public JsonOutput beginObject() {
stack.getFirst().write("{" + lineSeparator);
Expand All @@ -290,8 +302,12 @@ public JsonOutput beginObject() {
}

/**
* @param name
* @return
* Set the name of a new JSON object property.
*
* @param name JSON object property name
* @return this {@link JsonOutput} object
* @throws JsonException if top item on serialization object stack isn't a {@link JsonObject}
* @throws java.util.NoSuchElementException if serialization object stack is empty
*/
public JsonOutput name(String name) {
if (!(stack.getFirst() instanceof JsonObject)) {
Expand All @@ -302,7 +318,11 @@ public JsonOutput name(String name) {
}

/**
* @return
* End the current JSON object.
*
* @return this {@link JsonOutput} object
* @throws JsonException if top item on serialization object stack isn't a {@link JsonObject}
* @throws java.util.NoSuchElementException if serialization object stack is empty
*/
public JsonOutput endObject() {
Node topOfStack = stack.getFirst();
Expand All @@ -321,7 +341,9 @@ public JsonOutput endObject() {
}

/**
* @return
* Begin a new JSON array.
*
* @return this {@link JsonOutput} object
*/
public JsonOutput beginArray() {
append("[" + lineSeparator);
Expand All @@ -331,7 +353,11 @@ public JsonOutput beginArray() {
}

/**
* @return
* End the current JSON array.
*
* @return this {@link JsonOutput} object
* @throws JsonException if top item on serialization object stack isn't a {@link JsonCollection}
* @throws java.util.NoSuchElementException if serialization object stack is empty
*/
public JsonOutput endArray() {
Node topOfStack = stack.getFirst();
Expand All @@ -350,28 +376,30 @@ public JsonOutput endArray() {
}

/**
* @param value
* @return
* Serialize the specified Java object as a JSON value.<br>
* <b>NOTE</b>: This method limits traversal of nested objects to the default {@link #MAX_DEPTH
* maximum depth}.
*
* @param value Java object to serialize
* @return this {@link JsonOutput} object
* @throws JsonException if allowed depth has been reached
*/
public JsonOutput write(Object value) {
return write(value, MAX_DEPTH);
}

/**
* @param value
* @param maxDepth
* @return
* Serialize the specified Java object as a JSON value.
*
* @param value Java object to serialize
* @param maxDepth maximum depth of nested object traversal
* @return this {@link JsonOutput} object
* @throws JsonException if allowed depth has been reached
*/
public JsonOutput write(Object value, int maxDepth) {
return write0(value, maxDepth, maxDepth);
}

/**
* @param input
* @param maxDepth
* @param depthRemaining
* @return
*/
private JsonOutput write0(Object input, int maxDepth, int depthRemaining) {
converters.entrySet().stream()
.filter(entry -> entry.getKey().test(input == null ? null : input.getClass()))
Expand All @@ -387,6 +415,7 @@ private JsonOutput write0(Object input, int maxDepth, int depthRemaining) {
* {@inheritDoc}
*
* @throws JsonException if JSON stream isn't empty or an I/O exception is encountered
* @throws java.util.NoSuchElementException if serialization object stack is empty
*/
@Override
public void close() {
Expand All @@ -398,23 +427,21 @@ public void close() {
}
}

if (!(stack.getFirst() instanceof Empty)) {
if (!(stack.getFirst() instanceof Root)) {
throw new JsonException("Attempting to close incomplete json stream");
}
}

/**
* @param text
* @return
*/
private JsonOutput append(String text) {
stack.getFirst().write(text);
return this;
}

/**
* @param obj
* @return
* Return a quoted JSON string representing the specified Java object.
*
* @param obj Java object to be represented
* @return quoted JSON string
*/
private String asString(Object obj) {
StringBuilder toReturn = new StringBuilder("\"");
Expand All @@ -437,9 +464,13 @@ private String asString(Object obj) {
}

/**
* @param clazz
* @param methodName
* @return
* Get a reference to a method of the specified name with no argument in the indicated class or
* one of its ancestors.
*
* @param clazz target Java class
* @param methodName method name
* @return {@link Method} object with 'accessible' flag set
* @throws JsonException if a security violation is encountered
*/
private Method getMethod(Class<?> clazz, String methodName) {
if (Object.class.equals(clazz)) {
Expand All @@ -459,11 +490,20 @@ private Method getMethod(Class<?> clazz, String methodName) {
}

/**
* @param methodName
* @param toConvert
* @param maxDepth
* @param depthRemaining
* @return
* Convert the specified Java object using the indicated zero-argument method of this object.
*
* @param methodName method name
* @param toConvert Java object to be converted
* @param maxDepth maximum depth of nested object traversal
* @param depthRemaining allowed traversal depth remaining
* @return this {@link JsonOutput} object
* @throws JsonException
* <ul>
* <li>if the specified method isn't found
* <li>if a security violation is encountered
* <li>if a reflective operation fails
* <li>if maximum traversal depth is exceeded
* </ul>
*/
private JsonOutput convertUsingMethod(
String methodName, Object toConvert, int maxDepth, int depthRemaining) {
Expand All @@ -482,9 +522,13 @@ private JsonOutput convertUsingMethod(
}

/**
* @param toConvert
* @param maxDepth
* @param depthRemaining
* Convert the specified Java object via accessors that conform to the {@code JavaBean}
* specification.
*
* @param toConvert Java object to be converted
* @param maxDepth maximum depth of nested object traversal
* @param depthRemaining allowed traversal depth remaining
* @throws JsonException if allowed depth has been reached
*/
private void mapObject(Object toConvert, int maxDepth, int depthRemaining) {
if (toConvert instanceof Class) {
Expand Down Expand Up @@ -516,12 +560,17 @@ private void mapObject(Object toConvert, int maxDepth, int depthRemaining) {
endObject();
}

/** */
private class Node {
/** Defines to common behavior of JSON containers (objects and arrays). */
private abstract class Node {
protected boolean isEmpty = true;

/**
* @param text
* Write the specified text to the appender of this JSON output object.<br>
* <b>NOTE</b>: If prior text has been written to this container, the new text is prefixed with
* a comma and the defined line separator (either {@literal <newline>} or empty string) to
* delimit a new object property or array item.
*
* @param text text to be appended to the output
*/
public void write(String text) {
if (isEmpty) {
Expand All @@ -535,9 +584,15 @@ public void write(String text) {
}
}

/** */
private class Empty extends Node {
/** Represents the root of the JSON output. */
private class Root extends Node {

/**
* Write the specified text to the appender of this JSON output object.
*
* @param text text to be appended to the output
* @throws JsonException if this {@link JsonOutput} has already been used.
*/
@Override
public void write(String text) {
if (!isEmpty) {
Expand All @@ -548,15 +603,19 @@ public void write(String text) {
}
}

/** */
/** Represents a JSON array. */
private class JsonCollection extends Node {}

/** */
/** Represents a JSON object. */
private class JsonObject extends Node {
private boolean isNameNext = true;

/**
* @param name
* Writes the name of a JSON property followed by a colon to the appender of this JSON output
* object.
*
* @param name JSON object property name
* @throws JsonException if not expecting a new JSON property
*/
public void name(String name) {
if (!isNameNext) {
Expand All @@ -567,6 +626,12 @@ public void name(String name) {
appender.accept(": ");
}

/**
* Write the value of a JSON property to the appender of this JSON output object.
*
* @param text JSON object property value
* @throws JsonException if not expecting a JSON property value
*/
@Override
public void write(String text) {
if (isNameNext) {
Expand All @@ -578,14 +643,19 @@ public void write(String text) {
}
}

/** */
/**
* Defines the common interface for the Java object traversal serializers of {@link JsonOutput}.
*/
@FunctionalInterface
private interface DepthAwareConsumer {

/**
* @param object
* @param maxDepth
* @param depthRemaining
* Consume the specified Java object, emitting its JSON representation to the appender of this
* {@link JsonOutput}.
*
* @param object Java object to be serialized
* @param maxDepth maximum depth of nested object traversal
* @param depthRemaining allowed traversal depth remaining
*/
void consume(Object object, int maxDepth, int depthRemaining);
}
Expand Down

0 comments on commit 327785f

Please sign in to comment.