Skip to content

Commit 75ee094

Browse files
authored
fix: Possible NPE in initBiDi() (#2325)
1 parent db431d8 commit 75ee094

File tree

2 files changed

+57
-17
lines changed

2 files changed

+57
-17
lines changed

src/main/java/io/appium/java_client/remote/AppiumCommandExecutor.java

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import io.appium.java_client.AppiumClientConfig;
2121
import io.appium.java_client.internal.ReflectionHelpers;
2222
import lombok.Getter;
23-
import org.jspecify.annotations.NonNull;
23+
import org.jspecify.annotations.NullMarked;
2424
import org.jspecify.annotations.Nullable;
2525
import org.openqa.selenium.SessionNotCreatedException;
2626
import org.openqa.selenium.WebDriverException;
@@ -53,45 +53,43 @@
5353
import static java.util.Optional.ofNullable;
5454
import static org.openqa.selenium.remote.DriverCommand.NEW_SESSION;
5555

56+
@NullMarked
5657
public class AppiumCommandExecutor extends HttpCommandExecutor {
5758

5859
private final Optional<DriverService> serviceOptional;
5960
@Getter
60-
private final HttpClient.Factory httpClientFactory;
61-
@Getter
6261
private final AppiumClientConfig appiumClientConfig;
6362

6463
/**
6564
* Create an AppiumCommandExecutor instance.
6665
*
6766
* @param additionalCommands is the map of Appium commands
6867
* @param service take a look at {@link DriverService}
69-
* @param httpClientFactory take a look at {@link HttpClient.Factory}
68+
* @param httpClientFactory take a look at {@link Factory}
7069
* @param appiumClientConfig take a look at {@link AppiumClientConfig}
7170
*/
7271
public AppiumCommandExecutor(
73-
@NonNull Map<String, CommandInfo> additionalCommands,
72+
Map<String, CommandInfo> additionalCommands,
7473
@Nullable DriverService service,
7574
@Nullable Factory httpClientFactory,
76-
@NonNull AppiumClientConfig appiumClientConfig) {
75+
AppiumClientConfig appiumClientConfig) {
7776
super(additionalCommands,
7877
appiumClientConfig,
79-
ofNullable(httpClientFactory).orElseGet(AppiumCommandExecutor::getDefaultClientFactory)
78+
ofNullable(httpClientFactory).orElseGet(HttpCommandExecutor::getDefaultClientFactory)
8079
);
8180
serviceOptional = ofNullable(service);
8281

83-
this.httpClientFactory = httpClientFactory;
8482
this.appiumClientConfig = appiumClientConfig;
8583
}
8684

8785
public AppiumCommandExecutor(Map<String, CommandInfo> additionalCommands, DriverService service,
88-
HttpClient.Factory httpClientFactory) {
86+
@Nullable Factory httpClientFactory) {
8987
this(additionalCommands, requireNonNull(service), httpClientFactory,
9088
AppiumClientConfig.defaultConfig().baseUrl(requireNonNull(service).getUrl()));
9189
}
9290

9391
public AppiumCommandExecutor(Map<String, CommandInfo> additionalCommands, URL addressOfRemoteServer,
94-
HttpClient.Factory httpClientFactory) {
92+
@Nullable Factory httpClientFactory) {
9593
this(additionalCommands, null, httpClientFactory,
9694
AppiumClientConfig.defaultConfig().baseUrl(requireNonNull(addressOfRemoteServer)));
9795
}
@@ -140,6 +138,11 @@ public Map<String, CommandInfo> getAdditionalCommands() {
140138
return getPrivateFieldValue(HttpCommandExecutor.class, "additionalCommands", Map.class);
141139
}
142140

141+
public Factory getHttpClientFactory() {
142+
return getPrivateFieldValue(HttpCommandExecutor.class, "httpClientFactory", Factory.class);
143+
}
144+
145+
@Nullable
143146
protected CommandCodec<HttpRequest> getCommandCodec() {
144147
return this.commandCodec;
145148
}
@@ -163,12 +166,8 @@ protected HttpClient getClient() {
163166
* @param serverUrl A url to override.
164167
*/
165168
protected void overrideServerUrl(URL serverUrl) {
166-
if (this.appiumClientConfig == null) {
167-
return;
168-
}
169-
setPrivateFieldValue(HttpCommandExecutor.class, "client",
170-
ofNullable(this.httpClientFactory).orElseGet(AppiumCommandExecutor::getDefaultClientFactory)
171-
.createClient(this.appiumClientConfig.baseUrl(serverUrl)));
169+
HttpClient newClient = getHttpClientFactory().createClient(appiumClientConfig.baseUrl(serverUrl));
170+
setPrivateFieldValue(HttpCommandExecutor.class, "client", newClient);
172171
}
173172

174173
private Response createSession(Command command) throws IOException {
@@ -186,7 +185,7 @@ private Response createSession(Command command) throws IOException {
186185
refreshAdditionalCommands();
187186
setResponseCodec(dialect.getResponseCodec());
188187
Response response = result.createResponse();
189-
if (this.appiumClientConfig != null && this.appiumClientConfig.isDirectConnectEnabled()) {
188+
if (appiumClientConfig.isDirectConnectEnabled()) {
190189
setDirectConnect(response);
191190
}
192191

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package io.appium.java_client.remote;
2+
3+
import io.appium.java_client.AppiumClientConfig;
4+
import io.appium.java_client.MobileCommand;
5+
import org.junit.jupiter.api.Test;
6+
7+
import java.net.MalformedURLException;
8+
import java.net.URL;
9+
10+
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
11+
import static org.junit.jupiter.api.Assertions.assertNotNull;
12+
13+
class AppiumCommandExecutorTest {
14+
private static final String APPIUM_URL = "https://appium.example.com";
15+
16+
private AppiumCommandExecutor createExecutor() {
17+
URL baseUrl;
18+
try {
19+
baseUrl = new URL(APPIUM_URL);
20+
} catch (MalformedURLException e) {
21+
throw new AssertionError(e);
22+
}
23+
AppiumClientConfig clientConfig = AppiumClientConfig.defaultConfig().baseUrl(baseUrl);
24+
return new AppiumCommandExecutor(MobileCommand.commandRepository, clientConfig);
25+
}
26+
27+
@Test
28+
void getAdditionalCommands() {
29+
assertNotNull(createExecutor().getAdditionalCommands());
30+
}
31+
32+
@Test
33+
void getHttpClientFactory() {
34+
assertNotNull(createExecutor().getHttpClientFactory());
35+
}
36+
37+
@Test
38+
void overrideServerUrl() {
39+
assertDoesNotThrow(() -> createExecutor().overrideServerUrl(new URL("https://direct.example.com")));
40+
}
41+
}

0 commit comments

Comments
 (0)