Skip to content

Commit b5b093e

Browse files
authored
Replace Calendar.getInstance with System.currentTimeMillis for breadcrumb ctor (#3736)
1 parent 7e57220 commit b5b093e

File tree

4 files changed

+35
-8
lines changed

4 files changed

+35
-8
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
- For example, (this is already a default behavior) to redact all `TextView`s and their subclasses (`RadioButton`, `EditText`, etc.): `options.experimental.sessionReplay.addRedactViewClass("android.widget.TextView")`
2020
- If you're using code obfuscation, adjust your proguard-rules accordingly, so your custom view class name is not minified
2121
- Fix ensure Application Context is used even when SDK is initialized via Activity Context ([#3669](https://github.com/getsentry/sentry-java/pull/3669))
22+
- Fix potential ANRs due to `Calendar.getInstance` usage in Breadcrumbs constructor ([#3736](https://github.com/getsentry/sentry-java/pull/3736))
2223

2324
*Breaking changes*:
2425

sentry/api/sentry.api

+1
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ public final class io/sentry/BaggageHeader {
9898

9999
public final class io/sentry/Breadcrumb : io/sentry/JsonSerializable, io/sentry/JsonUnknown {
100100
public fun <init> ()V
101+
public fun <init> (J)V
101102
public fun <init> (Ljava/lang/String;)V
102103
public fun <init> (Ljava/util/Date;)V
103104
public static fun debug (Ljava/lang/String;)Lio/sentry/Breadcrumb;

sentry/src/main/java/io/sentry/Breadcrumb.java

+26-8
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@
1919
/** Series of application events */
2020
public final class Breadcrumb implements JsonUnknown, JsonSerializable {
2121

22-
/** A timestamp representing when the breadcrumb occurred. */
23-
private final @NotNull Date timestamp;
22+
/** A timestamp representing when the breadcrumb occurred in milliseconds. */
23+
private @Nullable final Long timestampMs;
24+
25+
/** A timestamp representing when the breadcrumb occurred as java.util.Date. */
26+
private @Nullable Date timestamp;
2427

2528
/** If a message is provided, its rendered as text and the whitespace is preserved. */
2629
private @Nullable String message;
@@ -51,12 +54,20 @@ public final class Breadcrumb implements JsonUnknown, JsonSerializable {
5154
*
5255
* @param timestamp the timestamp
5356
*/
57+
@SuppressWarnings("JavaUtilDate")
5458
public Breadcrumb(final @NotNull Date timestamp) {
5559
this.timestamp = timestamp;
60+
this.timestampMs = null;
61+
}
62+
63+
public Breadcrumb(final long timestamp) {
64+
this.timestampMs = timestamp;
65+
this.timestamp = null;
5666
}
5767

5868
Breadcrumb(final @NotNull Breadcrumb breadcrumb) {
5969
this.timestamp = breadcrumb.timestamp;
70+
this.timestampMs = breadcrumb.timestampMs;
6071
this.message = breadcrumb.message;
6172
this.type = breadcrumb.type;
6273
this.category = breadcrumb.category;
@@ -504,7 +515,7 @@ public static Breadcrumb fromMap(
504515

505516
/** Breadcrumb ctor */
506517
public Breadcrumb() {
507-
this(DateUtils.getCurrentDateTime());
518+
this(System.currentTimeMillis());
508519
}
509520

510521
/**
@@ -518,13 +529,20 @@ public Breadcrumb(@Nullable String message) {
518529
}
519530

520531
/**
521-
* Returns the Breadcrumb's timestamp
532+
* Returns the Breadcrumb's timestamp as java.util.Date
522533
*
523534
* @return the timestamp
524535
*/
525-
@SuppressWarnings({"JdkObsolete", "JavaUtilDate"})
536+
@SuppressWarnings("JavaUtilDate")
526537
public @NotNull Date getTimestamp() {
527-
return (Date) timestamp.clone();
538+
if (timestamp != null) {
539+
return (Date) timestamp.clone();
540+
} else if (timestampMs != null) {
541+
// we memoize it here into timestamp to avoid instantiating Calendar again and again
542+
timestamp = DateUtils.getDateTime(timestampMs);
543+
return timestamp;
544+
}
545+
throw new IllegalStateException("No timestamp set for breadcrumb");
528546
}
529547

530548
/**
@@ -664,7 +682,7 @@ public boolean equals(Object o) {
664682
if (this == o) return true;
665683
if (o == null || getClass() != o.getClass()) return false;
666684
Breadcrumb that = (Breadcrumb) o;
667-
return timestamp.getTime() == that.timestamp.getTime()
685+
return getTimestamp().getTime() == that.getTimestamp().getTime()
668686
&& Objects.equals(message, that.message)
669687
&& Objects.equals(type, that.type)
670688
&& Objects.equals(category, that.category)
@@ -704,7 +722,7 @@ public static final class JsonKeys {
704722
public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger)
705723
throws IOException {
706724
writer.beginObject();
707-
writer.name(JsonKeys.TIMESTAMP).value(logger, timestamp);
725+
writer.name(JsonKeys.TIMESTAMP).value(logger, getTimestamp());
708726
if (message != null) {
709727
writer.name(JsonKeys.MESSAGE).value(message);
710728
}

sentry/src/test/java/io/sentry/BreadcrumbTest.kt

+7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.sentry
22

3+
import java.util.Date
34
import kotlin.test.Test
45
import kotlin.test.assertEquals
56
import kotlin.test.assertFalse
@@ -100,6 +101,12 @@ class BreadcrumbTest {
100101
assertNotNull(breadcrumb.timestamp)
101102
}
102103

104+
@Test
105+
fun `breadcrumb can be created with Date timestamp`() {
106+
val breadcrumb = Breadcrumb(Date(123L))
107+
assertEquals(123L, breadcrumb.timestamp.time)
108+
}
109+
103110
@Test
104111
fun `breadcrumb takes message on ctor`() {
105112
val breadcrumb = Breadcrumb("this is a test")

0 commit comments

Comments
 (0)