diff --git a/sentry/src/main/java/io/sentry/util/LoadClass.java b/sentry/src/main/java/io/sentry/util/LoadClass.java index 2c39cace39..bf179fad45 100644 --- a/sentry/src/main/java/io/sentry/util/LoadClass.java +++ b/sentry/src/main/java/io/sentry/util/LoadClass.java @@ -4,6 +4,7 @@ import io.sentry.ILogger; import io.sentry.SentryLevel; import io.sentry.SentryOptions; +import java.util.Map; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -11,6 +12,9 @@ @Open public class LoadClass { + // Populated by the Sentry Android Gradle plugin for class names it can resolve at build time. + static @Nullable Map classAvailability; + /** * Loads and initializes a class via reflection. Use this when you intend to actually use the * class (e.g. instantiate it or invoke its methods). The returned class is fully initialized, so @@ -57,6 +61,16 @@ public class LoadClass { * @return true if the class is on the classpath */ public boolean isClassAvailable(final @NotNull String clazz, final @Nullable ILogger logger) { + final @Nullable Map availability = classAvailability; + if (availability != null) { + final @Nullable Boolean available = availability.get(clazz); + if (available != null) { + if (!available && logger != null) { + logger.log(SentryLevel.INFO, "Class not available: " + clazz); + } + return available; + } + } return loadClass(clazz, logger, false) != null; } diff --git a/sentry/src/test/java/io/sentry/util/LoadClassTest.kt b/sentry/src/test/java/io/sentry/util/LoadClassTest.kt index 7a8bc80204..4cb921feff 100644 --- a/sentry/src/test/java/io/sentry/util/LoadClassTest.kt +++ b/sentry/src/test/java/io/sentry/util/LoadClassTest.kt @@ -1,5 +1,6 @@ package io.sentry.util +import com.google.common.truth.Truth.assertThat import kotlin.test.Test import kotlin.test.assertFalse import kotlin.test.assertNotNull @@ -7,6 +8,32 @@ import kotlin.test.assertNull import kotlin.test.assertTrue class LoadClassTest { + @Test + fun `isClassAvailable uses known build-time results and reflects unknown classes`() { + LoadClass.classAvailability = + mapOf( + "io.sentry.SentryEvent" to false, + "io.sentry.ThisClassDoesNotExist" to true, + ) + + try { + val loadClass = LoadClass() + assertThat(loadClass.isClassAvailable("io.sentry.SentryEvent", null as io.sentry.ILogger?)) + .isFalse() + assertThat( + loadClass.isClassAvailable( + "io.sentry.ThisClassDoesNotExist", + null as io.sentry.ILogger?, + ) + ) + .isTrue() + assertThat(loadClass.isClassAvailable("io.sentry.Sentry", null as io.sentry.ILogger?)) + .isTrue() + } finally { + LoadClass.classAvailability = null + } + } + @Test fun `loadClass returns the class when it is available`() { assertNotNull(LoadClass().loadClass("io.sentry.SentryEvent", null))