From 2de332fd0b5373f43211b701496f4736bd44100f Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Wed, 30 Sep 2026 20:55:21 +0200 Subject: [PATCH] build: replace selenium-json's Json with Gson at the 3 call sites Phase 2 of removing the Selenium dependency footprint: AppiumBy, LogsEvents and StorageClient each used org.openqa.selenium.json.Json for plain Map<->JSON conversion. Swapped for the gson dependency the project already declares directly, with no wrapper class since there are only 3 call sites. Doesn't shrink the dependency graph yet (selenium-json is also used internally by selenium-remote-driver's codecs until a later phase). Co-Authored-By: Claude Sonnet 5 --- .../java/io/appium/java_client/AppiumBy.java | 6 +-- .../io/appium/java_client/LogsEvents.java | 4 +- .../plugins/storage/StorageClient.java | 11 +++-- .../AppiumByFlutterHierarchyTest.java | 42 +++++++++++++++++++ 4 files changed, 54 insertions(+), 9 deletions(-) create mode 100644 src/test/java/io/appium/java_client/AppiumByFlutterHierarchyTest.java diff --git a/src/main/java/io/appium/java_client/AppiumBy.java b/src/main/java/io/appium/java_client/AppiumBy.java index 1c24b29c1..5a8f63a45 100644 --- a/src/main/java/io/appium/java_client/AppiumBy.java +++ b/src/main/java/io/appium/java_client/AppiumBy.java @@ -17,13 +17,13 @@ package io.appium.java_client; import com.google.common.base.Preconditions; +import com.google.gson.Gson; import lombok.EqualsAndHashCode; import lombok.Getter; import org.openqa.selenium.By; import org.openqa.selenium.By.Remotable; import org.openqa.selenium.SearchContext; import org.openqa.selenium.WebElement; -import org.openqa.selenium.json.Json; import java.io.Serializable; import java.util.HashMap; @@ -383,7 +383,7 @@ protected FlutterBy(String selector, String locatorString, String locatorName) { } public abstract static class FlutterByHierarchy extends FlutterBy { - private static final Json JSON = new Json(); + private static final Gson GSON = new Gson(); protected FlutterByHierarchy( String selector, @@ -404,7 +404,7 @@ static String formatLocator(FlutterBy of, FlutterBy matching, Map value = (Map) response.getValue(); diff --git a/src/main/java/io/appium/java_client/plugins/storage/StorageClient.java b/src/main/java/io/appium/java_client/plugins/storage/StorageClient.java index 013782ec8..cf67473b8 100644 --- a/src/main/java/io/appium/java_client/plugins/storage/StorageClient.java +++ b/src/main/java/io/appium/java_client/plugins/storage/StorageClient.java @@ -16,8 +16,9 @@ package io.appium.java_client.plugins.storage; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; import org.openqa.selenium.WebDriverException; -import org.openqa.selenium.json.Json; import org.openqa.selenium.remote.ErrorCodec; import org.openqa.selenium.remote.codec.AbstractHttpResponseCodec; import org.openqa.selenium.remote.codec.w3c.W3CHttpResponseCodec; @@ -31,6 +32,7 @@ import org.openqa.selenium.remote.http.WebSocket; import java.io.File; +import java.lang.reflect.Type; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; @@ -54,7 +56,8 @@ */ public class StorageClient { public static final String PREFIX = "/storage"; - private final Json json = new Json(); + private static final Type MAP_TYPE = new TypeToken>() { }.getType(); + private final Gson gson = new Gson(); private final AbstractHttpResponseCodec responseCodec = new W3CHttpResponseCodec(); private final ErrorCodec errorCodec = ErrorCodec.createDefault(); @@ -186,7 +189,7 @@ private static URL formatPath(URL url, String... suffixes) { } private HttpRequest setJsonPayload(HttpRequest request, Map payload) { - var strData = json.toJson(payload); + var strData = gson.toJson(payload); var data = strData.getBytes(StandardCharsets.UTF_8); request.setHeader(HttpHeader.ContentLength.getName(), String.valueOf(data.length)); request.setHeader(HttpHeader.ContentType.getName(), "application/json; charset=utf-8"); @@ -233,7 +236,7 @@ public void onError(Throwable cause) { private Optional extractException(String payload) { try { - Map record = json.toType(payload, Json.MAP_TYPE); + Map record = gson.fromJson(payload, MAP_TYPE); //noinspection unchecked var value = (Map) record.get("value"); if ((Boolean) value.get("success")) { diff --git a/src/test/java/io/appium/java_client/AppiumByFlutterHierarchyTest.java b/src/test/java/io/appium/java_client/AppiumByFlutterHierarchyTest.java new file mode 100644 index 000000000..168443b44 --- /dev/null +++ b/src/test/java/io/appium/java_client/AppiumByFlutterHierarchyTest.java @@ -0,0 +1,42 @@ +package io.appium.java_client; + +import com.google.gson.Gson; +import org.junit.jupiter.api.Test; + +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class AppiumByFlutterHierarchyTest { + + private final Gson gson = new Gson(); + + @Test + void flutterDescendantLocatorIsValidJsonWithExpectedShape() { + AppiumBy.FlutterBy of = AppiumBy.flutterType("myType"); + AppiumBy.FlutterBy matching = AppiumBy.flutterText("myText"); + + String locatorString = (String) AppiumBy.flutterDescendant(of, matching, true, false) + .getRemoteParameters().value(); + + @SuppressWarnings("unchecked") + Map locator = gson.fromJson(locatorString, Map.class); + assertEquals(Map.of("using", "-flutter type", "value", "myType"), locator.get("of")); + assertEquals(Map.of("using", "-flutter text", "value", "myText"), locator.get("matching")); + assertEquals(Map.of("matchRoot", true, "skipOffstage", false), locator.get("parameters")); + } + + @Test + void flutterAncestorLocatorIsValidJsonWithExpectedShape() { + AppiumBy.FlutterBy of = AppiumBy.flutterKey("myKey"); + AppiumBy.FlutterBy matching = AppiumBy.flutterSemanticsLabel("myLabel"); + + String locatorString = (String) AppiumBy.flutterAncestor(of, matching, true).getRemoteParameters().value(); + + @SuppressWarnings("unchecked") + Map locator = gson.fromJson(locatorString, Map.class); + assertEquals(Map.of("using", "-flutter key", "value", "myKey"), locator.get("of")); + assertEquals(Map.of("using", "-flutter semantics label", "value", "myLabel"), locator.get("matching")); + assertEquals(Map.of("matchRoot", true), locator.get("parameters")); + } +}