Skip to content

Commit cda0e9d

Browse files
committed
android: Use Provider to construct OkHttpChannelBuilder
Doing any reflection on OkHttpChannelBuilder requires that all methods can have their arguments resolved. We'd like to make okhttp an optional dependency (to support okhttp 2 and 3/4 simultaneously). But making okhttp optional means we can no longer construct OkHttpChannelBuilder reflectively. We swap to the Provider that doesn't have this problem. See grpc#8971. Note that ManagedChannelProvider itself only exposes its methods as protected, so they wouldn't be accessible. However OkHttpChannelProvider has its methods public. It is an open question of whether ManagedChannelProvider's methods should become public, but in any case we can hide a public OkHttpChannelProvider inside a package-private class so it is only accessable via reflection. So this code assuming public methods doesn't prevent future implementation hiding.
1 parent 6c00f00 commit cda0e9d

File tree

1 file changed

+27
-8
lines changed

1 file changed

+27
-8
lines changed

android/src/main/java/io/grpc/android/AndroidChannelBuilder.java

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,33 @@ public final class AndroidChannelBuilder extends ForwardingChannelBuilder<Androi
5555

5656
private static final String LOG_TAG = "AndroidChannelBuilder";
5757

58-
@Nullable private static final Class<?> OKHTTP_CHANNEL_BUILDER_CLASS = findOkHttp();
58+
@Nullable private static final Object OKHTTP_CHANNEL_PROVIDER = findOkHttp();
5959

60-
private static Class<?> findOkHttp() {
60+
private static Object findOkHttp() {
61+
Class<?> klass;
6162
try {
62-
return Class.forName("io.grpc.okhttp.OkHttpChannelBuilder");
63+
klass = Class.forName("io.grpc.okhttp.OkHttpChannelProvider");
6364
} catch (ClassNotFoundException e) {
65+
Log.w(LOG_TAG, "Failed to find OkHttpChannelProvider", e);
6466
return null;
6567
}
68+
Object provider;
69+
try {
70+
provider = klass.getConstructor().newInstance();
71+
} catch (Exception e) {
72+
Log.w(LOG_TAG, "Failed to construct OkHttpChannelProvider", e);
73+
return null;
74+
}
75+
try {
76+
if (!(Boolean) klass.getMethod("isAvailable").invoke(provider)) {
77+
Log.w(LOG_TAG, "OkHttpChannelProvider.isAvailable() returned false");
78+
return null;
79+
}
80+
} catch (Exception e) {
81+
Log.w(LOG_TAG, "Failed to check OkHttpChannelProvider.isAvailable()", e);
82+
return null;
83+
}
84+
return provider;
6685
}
6786

6887
private final ManagedChannelBuilder<?> delegateBuilder;
@@ -113,15 +132,15 @@ public static AndroidChannelBuilder usingBuilder(ManagedChannelBuilder<?> builde
113132
}
114133

115134
private AndroidChannelBuilder(String target) {
116-
if (OKHTTP_CHANNEL_BUILDER_CLASS == null) {
117-
throw new UnsupportedOperationException("No ManagedChannelBuilder found on the classpath");
135+
if (OKHTTP_CHANNEL_PROVIDER == null) {
136+
throw new UnsupportedOperationException("Unable to load OkHttpChannelProvider");
118137
}
119138
try {
120139
delegateBuilder =
121140
(ManagedChannelBuilder)
122-
OKHTTP_CHANNEL_BUILDER_CLASS
123-
.getMethod("forTarget", String.class)
124-
.invoke(null, target);
141+
OKHTTP_CHANNEL_PROVIDER.getClass()
142+
.getMethod("builderForTarget", String.class)
143+
.invoke(OKHTTP_CHANNEL_PROVIDER, target);
125144
} catch (Exception e) {
126145
throw new RuntimeException("Failed to create ManagedChannelBuilder", e);
127146
}

0 commit comments

Comments
 (0)