Skip to content

Commit

Permalink
android: Use Provider to construct OkHttpChannelBuilder
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
ejona86 committed Mar 21, 2022
1 parent 012dbaf commit e74a794
Showing 1 changed file with 27 additions and 8 deletions.
35 changes: 27 additions & 8 deletions android/src/main/java/io/grpc/android/AndroidChannelBuilder.java
Expand Up @@ -55,14 +55,33 @@ public final class AndroidChannelBuilder extends ForwardingChannelBuilder<Androi

private static final String LOG_TAG = "AndroidChannelBuilder";

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

private static Class<?> findOkHttp() {
private static Object findOkHttp() {
Class<?> klass;
try {
return Class.forName("io.grpc.okhttp.OkHttpChannelBuilder");
klass = Class.forName("io.grpc.okhttp.OkHttpChannelProvider");
} catch (ClassNotFoundException e) {
Log.w(LOG_TAG, "Failed to find OkHttpChannelProvider", e);
return null;
}
Object provider;
try {
provider = klass.getConstructor().newInstance();
} catch (Exception e) {
Log.w(LOG_TAG, "Failed constructing OkHttpChannelProvider", e);
return null;
}
try {
if (!(Boolean) klass.getMethod("isAvailable").invoke(provider)) {
Log.w(LOG_TAG, "OkHttpChannelProvider.isAvailable() returned false");
return null;
}
} catch (Exception e) {
Log.w(LOG_TAG, "Failed checking OkHttpChannelProvider.isAvailable()", e);
return null;
}
return provider;
}

private final ManagedChannelBuilder<?> delegateBuilder;
Expand Down Expand Up @@ -113,15 +132,15 @@ public static AndroidChannelBuilder usingBuilder(ManagedChannelBuilder<?> builde
}

private AndroidChannelBuilder(String target) {
if (OKHTTP_CHANNEL_BUILDER_CLASS == null) {
throw new UnsupportedOperationException("No ManagedChannelBuilder found on the classpath");
if (OKHTTP_CHANNEL_PROVIDER == null) {
throw new UnsupportedOperationException("Unable to load OkHttpChannelProvider");
}
try {
delegateBuilder =
(ManagedChannelBuilder)
OKHTTP_CHANNEL_BUILDER_CLASS
.getMethod("forTarget", String.class)
.invoke(null, target);
OKHTTP_CHANNEL_PROVIDER.getClass()
.getMethod("builderForTarget", String.class)
.invoke(OKHTTP_CHANNEL_PROVIDER, target);
} catch (Exception e) {
throw new RuntimeException("Failed to create ManagedChannelBuilder", e);
}
Expand Down

0 comments on commit e74a794

Please sign in to comment.