diff --git a/java/src/org/openqa/selenium/json/JsonInput.java b/java/src/org/openqa/selenium/json/JsonInput.java index 5dfd52adb3009..9334bff9fe1e3 100644 --- a/java/src/org/openqa/selenium/json/JsonInput.java +++ b/java/src/org/openqa/selenium/json/JsonInput.java @@ -46,16 +46,6 @@ public class JsonInput implements Closeable { // figuring out whether we're expecting a NAME properly. private final Deque stack = new ArrayDeque<>(); - /** - * This package-private constructor initializes new instances of the {@code JsonInput} class.
- * 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); diff --git a/java/src/org/openqa/selenium/json/JsonOutput.java b/java/src/org/openqa/selenium/json/JsonOutput.java index 3827914f454f6..e62a785a5730e 100644 --- a/java/src/org/openqa/selenium/json/JsonOutput.java +++ b/java/src/org/openqa/selenium/json/JsonOutput.java @@ -46,7 +46,10 @@ import org.openqa.selenium.internal.Require; import org.openqa.selenium.logging.LogLevelMapping; -/** */ +/** + * The JsonOutput 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; @@ -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>, DepthAwareConsumer> builder = new LinkedHashMap<>(); builder.put(Objects::isNull, (obj, maxDepth, depthRemaining) -> append("null")); @@ -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" : ""; @@ -271,8 +278,11 @@ 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; @@ -280,7 +290,9 @@ public JsonOutput writeClassName(boolean writeClassName) { } /** - * @return + * Begin a new JSON object. + * + * @return this {@link JsonOutput} object */ public JsonOutput beginObject() { stack.getFirst().write("{" + lineSeparator); @@ -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)) { @@ -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(); @@ -321,7 +341,9 @@ public JsonOutput endObject() { } /** - * @return + * Begin a new JSON array. + * + * @return this {@link JsonOutput} object */ public JsonOutput beginArray() { append("[" + lineSeparator); @@ -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(); @@ -350,28 +376,30 @@ public JsonOutput endArray() { } /** - * @param value - * @return + * Serialize the specified Java object as a JSON value.
+ * NOTE: 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())) @@ -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() { @@ -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("\""); @@ -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)) { @@ -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 + * */ private JsonOutput convertUsingMethod( String methodName, Object toConvert, int maxDepth, int depthRemaining) { @@ -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) { @@ -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.
+ * NOTE: If prior text has been written to this container, the new text is prefixed with + * a comma and the defined line separator (either {@literal } 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) { @@ -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) { @@ -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) { @@ -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) { @@ -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); } diff --git a/java/src/org/openqa/selenium/json/JsonTypeCoercer.java b/java/src/org/openqa/selenium/json/JsonTypeCoercer.java index b3b34fc5bb77a..290183d1a3ee1 100644 --- a/java/src/org/openqa/selenium/json/JsonTypeCoercer.java +++ b/java/src/org/openqa/selenium/json/JsonTypeCoercer.java @@ -42,7 +42,10 @@ import org.openqa.selenium.MutableCapabilities; import org.openqa.selenium.internal.Require; -/** */ +/** + * The JsonTypeCoercer class manages a collection of type coercers, providing a single source + * for obtaining functions to convert JSON strings into instances of their corresponding Java types. + */ class JsonTypeCoercer { private final Set> additionalCoercers; @@ -50,15 +53,10 @@ class JsonTypeCoercer { private final Map> knownCoercers = new ConcurrentHashMap<>(); - /** */ JsonTypeCoercer() { this(Stream.of()); } - /** - * @param coercer - * @param coercers - */ JsonTypeCoercer(JsonTypeCoercer coercer, Iterable> coercers) { this( Stream.concat( @@ -66,9 +64,6 @@ class JsonTypeCoercer { coercer.additionalCoercers.stream())); } - /** - * @param coercers - */ private JsonTypeCoercer(Stream> coercers) { this.additionalCoercers = coercers.collect(collectingAndThen(toSet(), Collections::unmodifiableSet)); @@ -145,15 +140,6 @@ private JsonTypeCoercer(Stream> coercers) { this.coercers = Collections.unmodifiableSet(builder); } - /** - * Deserialize the next JSON element as an object of the specified type. - * - * @param json 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 result type (as specified by [typeOfT]) - */ T coerce(JsonInput json, Type typeOfT, PropertySetting setter) { BiFunction coercer = knownCoercers.computeIfAbsent(typeOfT, this::buildCoercer); @@ -166,8 +152,11 @@ T coerce(JsonInput json, Type typeOfT, PropertySetting setter) { } /** - * @param type - * @return + * Extract the coercer that supports the specified type from the collection managed by this {@code + * JsonTypeCoercer}, returning a coercion function for the client to use. + * + * @param type data type for deserialization (class or {@link TypeToken}) + * @return {@link BiFunction} object to deserialize the specified Java type */ private BiFunction buildCoercer(Type type) { return coercers.stream() diff --git a/scripts/format.ps1 b/scripts/format.ps1 new file mode 100644 index 0000000000000..251ccb63a1d87 --- /dev/null +++ b/scripts/format.ps1 @@ -0,0 +1,20 @@ +# Code formatter. + +Set-StrictMode -Version 'Latest' +$ErrorActionPreference = 'Stop' + +function section($message) { + Write-Host "- $message" -ForegroundColor Green +} + +$GOOGLE_JAVA_FORMAT = (bazel run --run_under=echo //scripts:google-java-format) + +section "Buildifier" +Write-Host " buildifier" -ForegroundColor Green +bazel run //:buildifier + +section "Java" +Write-Host " google-java-format" -ForegroundColor Green +Get-ChildItem -Path "$PWD/java" -Include "*.java" -Recurse | ForEach-Object { + &"$GOOGLE_JAVA_FORMAT" --replace $_.FullName +}