Skip to content

Commit 1e904b2

Browse files
romtsncodex
andauthored
perf(core): Use build-time class availability (#5875)
* perf(core): Use build-time class availability Consult class availability data injected by build tooling before falling back to reflection. Keep the map nullable so consumers without supporting tooling preserve current behavior. Refs JAVA-654 Co-Authored-By: Codex <noreply@openai.com> * ref(core): Make class availability package-private Allow package-local tests to set class availability without reflection. Refs LINEAR-JAVA-654 Co-Authored-By: Codex <noreply@openai.com> --------- Co-authored-by: Codex <noreply@openai.com>
1 parent ba5f1d5 commit 1e904b2

2 files changed

Lines changed: 41 additions & 0 deletions

File tree

sentry/src/main/java/io/sentry/util/LoadClass.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@
44
import io.sentry.ILogger;
55
import io.sentry.SentryLevel;
66
import io.sentry.SentryOptions;
7+
import java.util.Map;
78
import org.jetbrains.annotations.NotNull;
89
import org.jetbrains.annotations.Nullable;
910

1011
/** An Adapter for making Class.forName testable */
1112
@Open
1213
public class LoadClass {
1314

15+
// Populated by the Sentry Android Gradle plugin for class names it can resolve at build time.
16+
static @Nullable Map<String, Boolean> classAvailability;
17+
1418
/**
1519
* Loads and initializes a class via reflection. Use this when you intend to actually use the
1620
* class (e.g. instantiate it or invoke its methods). The returned class is fully initialized, so
@@ -57,6 +61,16 @@ public class LoadClass {
5761
* @return true if the class is on the classpath
5862
*/
5963
public boolean isClassAvailable(final @NotNull String clazz, final @Nullable ILogger logger) {
64+
final @Nullable Map<String, Boolean> availability = classAvailability;
65+
if (availability != null) {
66+
final @Nullable Boolean available = availability.get(clazz);
67+
if (available != null) {
68+
if (!available && logger != null) {
69+
logger.log(SentryLevel.INFO, "Class not available: " + clazz);
70+
}
71+
return available;
72+
}
73+
}
6074
return loadClass(clazz, logger, false) != null;
6175
}
6276

sentry/src/test/java/io/sentry/util/LoadClassTest.kt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,39 @@
11
package io.sentry.util
22

3+
import com.google.common.truth.Truth.assertThat
34
import kotlin.test.Test
45
import kotlin.test.assertFalse
56
import kotlin.test.assertNotNull
67
import kotlin.test.assertNull
78
import kotlin.test.assertTrue
89

910
class LoadClassTest {
11+
@Test
12+
fun `isClassAvailable uses known build-time results and reflects unknown classes`() {
13+
LoadClass.classAvailability =
14+
mapOf(
15+
"io.sentry.SentryEvent" to false,
16+
"io.sentry.ThisClassDoesNotExist" to true,
17+
)
18+
19+
try {
20+
val loadClass = LoadClass()
21+
assertThat(loadClass.isClassAvailable("io.sentry.SentryEvent", null as io.sentry.ILogger?))
22+
.isFalse()
23+
assertThat(
24+
loadClass.isClassAvailable(
25+
"io.sentry.ThisClassDoesNotExist",
26+
null as io.sentry.ILogger?,
27+
)
28+
)
29+
.isTrue()
30+
assertThat(loadClass.isClassAvailable("io.sentry.Sentry", null as io.sentry.ILogger?))
31+
.isTrue()
32+
} finally {
33+
LoadClass.classAvailability = null
34+
}
35+
}
36+
1037
@Test
1138
fun `loadClass returns the class when it is available`() {
1239
assertNotNull(LoadClass().loadClass("io.sentry.SentryEvent", null))

0 commit comments

Comments
 (0)