Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

api: Ignore ClassCastExceptions for hard-coded providers #9174

Merged
merged 1 commit into from May 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 14 additions & 3 deletions api/src/main/java/io/grpc/ServiceProviders.java
Expand Up @@ -122,15 +122,26 @@ public static <T> Iterable<T> getCandidatesViaServiceLoader(Class<T> klass, Clas
static <T> Iterable<T> getCandidatesViaHardCoded(Class<T> klass, Iterable<Class<?>> hardcoded) {
List<T> list = new ArrayList<>();
for (Class<?> candidate : hardcoded) {
list.add(create(klass, candidate));
T t = createForHardCoded(klass, candidate);
if (t == null) {
continue;
}
list.add(t);
}
return list;
}

@VisibleForTesting
static <T> T create(Class<T> klass, Class<?> rawClass) {
private static <T> T createForHardCoded(Class<T> klass, Class<?> rawClass) {
try {
return rawClass.asSubclass(klass).getConstructor().newInstance();
} catch (ClassCastException ex) {
// Tools like Proguard that perform obfuscation rewrite strings only when the class they
// reference is known, as otherwise they wouldn't know its new name. This means some
// hard-coded Class.forNames() won't be rewritten. This can cause ClassCastException at
// runtime if the class ends up appearing on the classpath but that class is part of a
// separate copy of grpc. With tools like Maven Shade Plugin the class wouldn't be found at
// all and so would be skipped. We want to skip in this case as well.
return null;
} catch (Throwable t) {
throw new ServiceConfigurationError(
String.format("Provider %s could not be instantiated %s", rawClass.getName(), t), t);
Expand Down
28 changes: 22 additions & 6 deletions api/src/test/java/io/grpc/ServiceProvidersTest.java
Expand Up @@ -215,19 +215,35 @@ public void getCandidatesViaHardCoded_failAtInit_moreCandidates() throws Excepti
}

@Test
public void create_throwsErrorOnMisconfiguration() throws Exception {
class PrivateClass {}
public void getCandidatesViaHardCoded_throwsErrorOnMisconfiguration() throws Exception {
class PrivateClass extends BaseProvider {
private PrivateClass() {
super(true, 5);
}
}

try {
ServiceProviders.create(
ServiceProvidersTestAbstractProvider.class, PrivateClass.class);
ServiceProviders.getCandidatesViaHardCoded(
ServiceProvidersTestAbstractProvider.class,
Collections.<Class<?>>singletonList(PrivateClass.class));
fail("Expected exception");
} catch (ServiceConfigurationError expected) {
assertTrue("Expected ClassCastException cause: " + expected.getCause(),
expected.getCause() instanceof ClassCastException);
assertTrue("Expected NoSuchMethodException cause: " + expected.getCause(),
expected.getCause() instanceof NoSuchMethodException);
}
}

@Test
public void getCandidatesViaHardCoded_skipsWrongClassType() throws Exception {
class RandomClass {}

Iterable<ServiceProvidersTestAbstractProvider> candidates =
ServiceProviders.getCandidatesViaHardCoded(
ServiceProvidersTestAbstractProvider.class,
Collections.<Class<?>>singletonList(RandomClass.class));
assertFalse(candidates.iterator().hasNext());
}

private static class BaseProvider extends ServiceProvidersTestAbstractProvider {
private final boolean isAvailable;
private final int priority;
Expand Down