From 254554aa29ffe05e9a516787e3bbfe83ed08755d Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Mon, 3 Jul 2023 13:23:29 +0200 Subject: [PATCH 01/10] Add MapObjectWriter to serialize protocol data to Java Map<> --- sentry/api/sentry.api | 183 ++++++++++---- .../src/main/java/io/sentry/Breadcrumb.java | 3 +- .../java/io/sentry/JsonObjectSerializer.java | 10 +- .../main/java/io/sentry/JsonObjectWriter.java | 78 +++++- .../main/java/io/sentry/JsonSerializable.java | 2 +- .../src/main/java/io/sentry/ObjectWriter.java | 33 +++ .../java/io/sentry/ProfilingTraceData.java | 2 +- .../io/sentry/ProfilingTransactionData.java | 3 +- sentry/src/main/java/io/sentry/Scope.java | 5 + sentry/src/main/java/io/sentry/ScopeUtil.java | 48 ++++ .../main/java/io/sentry/SentryBaseEvent.java | 4 +- .../java/io/sentry/SentryEnvelopeHeader.java | 3 +- .../io/sentry/SentryEnvelopeItemHeader.java | 3 +- .../src/main/java/io/sentry/SentryEvent.java | 3 +- .../main/java/io/sentry/SentryItemType.java | 3 +- .../src/main/java/io/sentry/SentryLevel.java | 3 +- .../main/java/io/sentry/SentryLockReason.java | 3 +- sentry/src/main/java/io/sentry/Session.java | 3 +- .../src/main/java/io/sentry/SpanContext.java | 3 +- sentry/src/main/java/io/sentry/SpanId.java | 3 +- .../src/main/java/io/sentry/SpanStatus.java | 3 +- .../src/main/java/io/sentry/TraceContext.java | 3 +- .../src/main/java/io/sentry/UserFeedback.java | 3 +- .../io/sentry/clientreport/ClientReport.java | 5 +- .../sentry/clientreport/DiscardedEvent.java | 5 +- .../ProfileMeasurement.java | 4 +- .../ProfileMeasurementValue.java | 4 +- .../src/main/java/io/sentry/protocol/App.java | 5 +- .../main/java/io/sentry/protocol/Browser.java | 5 +- .../java/io/sentry/protocol/Contexts.java | 4 +- .../java/io/sentry/protocol/DebugImage.java | 5 +- .../java/io/sentry/protocol/DebugMeta.java | 5 +- .../main/java/io/sentry/protocol/Device.java | 7 +- .../src/main/java/io/sentry/protocol/Geo.java | 4 +- .../src/main/java/io/sentry/protocol/Gpu.java | 5 +- .../io/sentry/protocol/MeasurementValue.java | 5 +- .../java/io/sentry/protocol/Mechanism.java | 5 +- .../main/java/io/sentry/protocol/Message.java | 5 +- .../io/sentry/protocol/OperatingSystem.java | 5 +- .../main/java/io/sentry/protocol/Request.java | 5 +- .../java/io/sentry/protocol/Response.java | 4 +- .../main/java/io/sentry/protocol/SdkInfo.java | 5 +- .../java/io/sentry/protocol/SdkVersion.java | 5 +- .../io/sentry/protocol/SentryException.java | 5 +- .../java/io/sentry/protocol/SentryId.java | 5 +- .../io/sentry/protocol/SentryPackage.java | 5 +- .../io/sentry/protocol/SentryRuntime.java | 5 +- .../java/io/sentry/protocol/SentrySpan.java | 5 +- .../io/sentry/protocol/SentryStackFrame.java | 5 +- .../io/sentry/protocol/SentryStackTrace.java | 5 +- .../java/io/sentry/protocol/SentryThread.java | 5 +- .../io/sentry/protocol/SentryTransaction.java | 5 +- .../io/sentry/protocol/TransactionInfo.java | 5 +- .../main/java/io/sentry/protocol/User.java | 5 +- .../io/sentry/protocol/ViewHierarchy.java | 5 +- .../io/sentry/protocol/ViewHierarchyNode.java | 5 +- .../java/io/sentry/util/MapObjectWriter.java | 236 ++++++++++++++++++ .../src/test/java/io/sentry/ScopeUtilTest.kt | 35 +++ .../SentryBaseEventSerializationTest.kt | 4 +- .../io/sentry/util/MapObjectWriterTest.kt | 168 +++++++++++++ 60 files changed, 820 insertions(+), 192 deletions(-) create mode 100644 sentry/src/main/java/io/sentry/ObjectWriter.java create mode 100644 sentry/src/main/java/io/sentry/ScopeUtil.java create mode 100644 sentry/src/main/java/io/sentry/util/MapObjectWriter.java create mode 100644 sentry/src/test/java/io/sentry/ScopeUtilTest.kt create mode 100644 sentry/src/test/java/io/sentry/util/MapObjectWriterTest.kt diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index 0e9d4c1a848..7d9c367575d 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -110,7 +110,7 @@ public final class io/sentry/Breadcrumb : io/sentry/JsonSerializable, io/sentry/ public static fun navigation (Ljava/lang/String;Ljava/lang/String;)Lio/sentry/Breadcrumb; public static fun query (Ljava/lang/String;)Lio/sentry/Breadcrumb; public fun removeData (Ljava/lang/String;)V - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setCategory (Ljava/lang/String;)V public fun setData (Ljava/lang/String;Ljava/lang/Object;)V public fun setLevel (Lio/sentry/SentryLevel;)V @@ -698,14 +698,38 @@ public final class io/sentry/JsonObjectSerializer { public static final field OBJECT_PLACEHOLDER Ljava/lang/String; public final field jsonReflectionObjectSerializer Lio/sentry/JsonReflectionObjectSerializer; public fun (I)V - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;Ljava/lang/Object;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;Ljava/lang/Object;)V } -public final class io/sentry/JsonObjectWriter : io/sentry/vendor/gson/stream/JsonWriter { +public final class io/sentry/JsonObjectWriter : io/sentry/ObjectWriter { public fun (Ljava/io/Writer;I)V + public fun beginArray ()Lio/sentry/JsonObjectWriter; + public synthetic fun beginArray ()Lio/sentry/ObjectWriter; + public fun beginObject ()Lio/sentry/JsonObjectWriter; + public synthetic fun beginObject ()Lio/sentry/ObjectWriter; + public fun endArray ()Lio/sentry/JsonObjectWriter; + public synthetic fun endArray ()Lio/sentry/ObjectWriter; + public fun endObject ()Lio/sentry/JsonObjectWriter; + public synthetic fun endObject ()Lio/sentry/ObjectWriter; public fun name (Ljava/lang/String;)Lio/sentry/JsonObjectWriter; - public synthetic fun name (Ljava/lang/String;)Lio/sentry/vendor/gson/stream/JsonWriter; + public synthetic fun name (Ljava/lang/String;)Lio/sentry/ObjectWriter; + public fun nullValue ()Lio/sentry/JsonObjectWriter; + public synthetic fun nullValue ()Lio/sentry/ObjectWriter; + public fun setIndent (Ljava/lang/String;)V + public fun value (D)Lio/sentry/JsonObjectWriter; + public synthetic fun value (D)Lio/sentry/ObjectWriter; + public fun value (J)Lio/sentry/JsonObjectWriter; + public synthetic fun value (J)Lio/sentry/ObjectWriter; public fun value (Lio/sentry/ILogger;Ljava/lang/Object;)Lio/sentry/JsonObjectWriter; + public synthetic fun value (Lio/sentry/ILogger;Ljava/lang/Object;)Lio/sentry/ObjectWriter; + public fun value (Ljava/lang/Boolean;)Lio/sentry/JsonObjectWriter; + public synthetic fun value (Ljava/lang/Boolean;)Lio/sentry/ObjectWriter; + public fun value (Ljava/lang/Number;)Lio/sentry/JsonObjectWriter; + public synthetic fun value (Ljava/lang/Number;)Lio/sentry/ObjectWriter; + public fun value (Ljava/lang/String;)Lio/sentry/JsonObjectWriter; + public synthetic fun value (Ljava/lang/String;)Lio/sentry/ObjectWriter; + public fun value (Z)Lio/sentry/JsonObjectWriter; + public synthetic fun value (Z)Lio/sentry/ObjectWriter; } public final class io/sentry/JsonReflectionObjectSerializer { @@ -714,7 +738,7 @@ public final class io/sentry/JsonReflectionObjectSerializer { } public abstract interface class io/sentry/JsonSerializable { - public abstract fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public abstract fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V } public final class io/sentry/JsonSerializer : io/sentry/ISerializer { @@ -960,6 +984,22 @@ public final class io/sentry/NoOpTransportFactory : io/sentry/ITransportFactory public static fun getInstance ()Lio/sentry/NoOpTransportFactory; } +public abstract interface class io/sentry/ObjectWriter { + public abstract fun beginArray ()Lio/sentry/ObjectWriter; + public abstract fun beginObject ()Lio/sentry/ObjectWriter; + public abstract fun endArray ()Lio/sentry/ObjectWriter; + public abstract fun endObject ()Lio/sentry/ObjectWriter; + public abstract fun name (Ljava/lang/String;)Lio/sentry/ObjectWriter; + public abstract fun nullValue ()Lio/sentry/ObjectWriter; + public abstract fun value (D)Lio/sentry/ObjectWriter; + public abstract fun value (J)Lio/sentry/ObjectWriter; + public abstract fun value (Lio/sentry/ILogger;Ljava/lang/Object;)Lio/sentry/ObjectWriter; + public abstract fun value (Ljava/lang/Boolean;)Lio/sentry/ObjectWriter; + public abstract fun value (Ljava/lang/Number;)Lio/sentry/ObjectWriter; + public abstract fun value (Ljava/lang/String;)Lio/sentry/ObjectWriter; + public abstract fun value (Z)Lio/sentry/ObjectWriter; +} + public final class io/sentry/OptionsContainer { public static fun create (Ljava/lang/Class;)Lio/sentry/OptionsContainer; public fun createInstance ()Ljava/lang/Object; @@ -1012,7 +1052,7 @@ public final class io/sentry/ProfilingTraceData : io/sentry/JsonSerializable, io public fun getUnknown ()Ljava/util/Map; public fun isDeviceIsEmulator ()Z public fun readDeviceCpuFrequencies ()V - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setAndroidApiLevel (I)V public fun setBuildId (Ljava/lang/String;)V public fun setCpuArchitecture (Ljava/lang/String;)V @@ -1086,7 +1126,7 @@ public final class io/sentry/ProfilingTransactionData : io/sentry/JsonSerializab public fun getUnknown ()Ljava/util/Map; public fun hashCode ()I public fun notifyFinish (Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;)V - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setId (Ljava/lang/String;)V public fun setName (Ljava/lang/String;)V public fun setRelativeEndNs (Ljava/lang/Long;)V @@ -1172,6 +1212,11 @@ public abstract interface class io/sentry/ScopeCallback { public abstract fun run (Lio/sentry/Scope;)V } +public final class io/sentry/ScopeUtil { + public fun ()V + public static fun serialize (Lio/sentry/Scope;)Ljava/util/Map; +} + public final class io/sentry/SendCachedEnvelopeFireAndForgetIntegration : io/sentry/Integration { public fun (Lio/sentry/SendCachedEnvelopeFireAndForgetIntegration$SendFireAndForgetFactory;)V public final fun register (Lio/sentry/IHub;Lio/sentry/SentryOptions;)V @@ -1346,7 +1391,7 @@ public final class io/sentry/SentryBaseEvent$JsonKeys { public final class io/sentry/SentryBaseEvent$Serializer { public fun ()V - public fun serialize (Lio/sentry/SentryBaseEvent;Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/SentryBaseEvent;Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V } public final class io/sentry/SentryClient : io/sentry/ISentryClient { @@ -1403,7 +1448,7 @@ public final class io/sentry/SentryEnvelopeHeader : io/sentry/JsonSerializable, public fun getSentAt ()Ljava/util/Date; public fun getTraceContext ()Lio/sentry/TraceContext; public fun getUnknown ()Ljava/util/Map; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setSentAt (Ljava/util/Date;)V public fun setUnknown (Ljava/util/Map;)V } @@ -1444,7 +1489,7 @@ public final class io/sentry/SentryEnvelopeItemHeader : io/sentry/JsonSerializab public fun getLength ()I public fun getType ()Lio/sentry/SentryItemType; public fun getUnknown ()Ljava/util/Map; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setUnknown (Ljava/util/Map;)V } @@ -1480,7 +1525,7 @@ public final class io/sentry/SentryEvent : io/sentry/SentryBaseEvent, io/sentry/ public fun isCrashed ()Z public fun isErrored ()Z public fun removeModule (Ljava/lang/String;)V - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setExceptions (Ljava/util/List;)V public fun setFingerprints (Ljava/util/List;)V public fun setLevel (Lio/sentry/SentryLevel;)V @@ -1552,7 +1597,7 @@ public final class io/sentry/SentryItemType : java/lang/Enum, io/sentry/JsonSeri public static final field UserFeedback Lio/sentry/SentryItemType; public fun getItemType ()Ljava/lang/String; public static fun resolve (Ljava/lang/Object;)Lio/sentry/SentryItemType; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public static fun valueOf (Ljava/lang/String;)Lio/sentry/SentryItemType; public static fun valueOfLabel (Ljava/lang/String;)Lio/sentry/SentryItemType; public static fun values ()[Lio/sentry/SentryItemType; @@ -1564,7 +1609,7 @@ public final class io/sentry/SentryLevel : java/lang/Enum, io/sentry/JsonSeriali public static final field FATAL Lio/sentry/SentryLevel; public static final field INFO Lio/sentry/SentryLevel; public static final field WARNING Lio/sentry/SentryLevel; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public static fun valueOf (Ljava/lang/String;)Lio/sentry/SentryLevel; public static fun values ()[Lio/sentry/SentryLevel; } @@ -1585,7 +1630,7 @@ public final class io/sentry/SentryLockReason : io/sentry/JsonSerializable, io/s public fun getType ()I public fun getUnknown ()Ljava/util/Map; public fun hashCode ()I - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setAddress (Ljava/lang/String;)V public fun setClassName (Ljava/lang/String;)V public fun setPackageName (Ljava/lang/String;)V @@ -1969,7 +2014,7 @@ public final class io/sentry/Session : io/sentry/JsonSerializable, io/sentry/Jso public fun getTimestamp ()Ljava/util/Date; public fun getUnknown ()Ljava/util/Map; public fun getUserAgent ()Ljava/lang/String; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setInitAsTrue ()V public fun setUnknown (Ljava/util/Map;)V public fun update (Lio/sentry/Session$State;Ljava/lang/String;Z)Z @@ -2084,7 +2129,7 @@ public class io/sentry/SpanContext : io/sentry/JsonSerializable, io/sentry/JsonU public fun getTraceId ()Lio/sentry/protocol/SentryId; public fun getUnknown ()Ljava/util/Map; public fun hashCode ()I - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setDescription (Ljava/lang/String;)V public fun setOperation (Ljava/lang/String;)V public fun setSampled (Ljava/lang/Boolean;)V @@ -2128,7 +2173,7 @@ public final class io/sentry/SpanId : io/sentry/JsonSerializable { public fun (Ljava/lang/String;)V public fun equals (Ljava/lang/Object;)Z public fun hashCode ()I - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun toString ()Ljava/lang/String; } @@ -2169,7 +2214,7 @@ public final class io/sentry/SpanStatus : java/lang/Enum, io/sentry/JsonSerializ public static final field UNKNOWN_ERROR Lio/sentry/SpanStatus; public static fun fromHttpStatusCode (I)Lio/sentry/SpanStatus; public static fun fromHttpStatusCode (Ljava/lang/Integer;Lio/sentry/SpanStatus;)Lio/sentry/SpanStatus; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public static fun valueOf (Ljava/lang/String;)Lio/sentry/SpanStatus; public static fun values ()[Lio/sentry/SpanStatus; } @@ -2198,7 +2243,7 @@ public final class io/sentry/TraceContext : io/sentry/JsonSerializable, io/sentr public fun getUnknown ()Ljava/util/Map; public fun getUserId ()Ljava/lang/String; public fun getUserSegment ()Ljava/lang/String; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setUnknown (Ljava/util/Map;)V } @@ -2339,7 +2384,7 @@ public final class io/sentry/UserFeedback : io/sentry/JsonSerializable, io/sentr public fun getEventId ()Lio/sentry/protocol/SentryId; public fun getName ()Ljava/lang/String; public fun getUnknown ()Ljava/util/Map; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setComments (Ljava/lang/String;)V public fun setEmail (Ljava/lang/String;)V public fun setName (Ljava/lang/String;)V @@ -2437,7 +2482,7 @@ public final class io/sentry/clientreport/ClientReport : io/sentry/JsonSerializa public fun getDiscardedEvents ()Ljava/util/List; public fun getTimestamp ()Ljava/util/Date; public fun getUnknown ()Ljava/util/Map; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setUnknown (Ljava/util/Map;)V } @@ -2480,7 +2525,7 @@ public final class io/sentry/clientreport/DiscardedEvent : io/sentry/JsonSeriali public fun getQuantity ()Ljava/lang/Long; public fun getReason ()Ljava/lang/String; public fun getUnknown ()Ljava/util/Map; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setUnknown (Ljava/util/Map;)V public fun toString ()Ljava/lang/String; } @@ -2760,7 +2805,7 @@ public final class io/sentry/profilemeasurements/ProfileMeasurement : io/sentry/ public fun getUnknown ()Ljava/util/Map; public fun getValues ()Ljava/util/Collection; public fun hashCode ()I - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setUnit (Ljava/lang/String;)V public fun setUnknown (Ljava/util/Map;)V public fun setValues (Ljava/util/Collection;)V @@ -2786,7 +2831,7 @@ public final class io/sentry/profilemeasurements/ProfileMeasurementValue : io/se public fun getUnknown ()Ljava/util/Map; public fun getValue ()D public fun hashCode ()I - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setUnknown (Ljava/util/Map;)V } @@ -2817,7 +2862,7 @@ public final class io/sentry/protocol/App : io/sentry/JsonSerializable, io/sentr public fun getPermissions ()Ljava/util/Map; public fun getUnknown ()Ljava/util/Map; public fun hashCode ()I - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setAppBuild (Ljava/lang/String;)V public fun setAppIdentifier (Ljava/lang/String;)V public fun setAppName (Ljava/lang/String;)V @@ -2857,7 +2902,7 @@ public final class io/sentry/protocol/Browser : io/sentry/JsonSerializable, io/s public fun getUnknown ()Ljava/util/Map; public fun getVersion ()Ljava/lang/String; public fun hashCode ()I - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setName (Ljava/lang/String;)V public fun setUnknown (Ljava/util/Map;)V public fun setVersion (Ljava/lang/String;)V @@ -2886,7 +2931,7 @@ public final class io/sentry/protocol/Contexts : java/util/concurrent/Concurrent public fun getResponse ()Lio/sentry/protocol/Response; public fun getRuntime ()Lio/sentry/protocol/SentryRuntime; public fun getTrace ()Lio/sentry/SpanContext; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setApp (Lio/sentry/protocol/App;)V public fun setBrowser (Lio/sentry/protocol/Browser;)V public fun setDevice (Lio/sentry/protocol/Device;)V @@ -2917,7 +2962,7 @@ public final class io/sentry/protocol/DebugImage : io/sentry/JsonSerializable, i public fun getType ()Ljava/lang/String; public fun getUnknown ()Ljava/util/Map; public fun getUuid ()Ljava/lang/String; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setArch (Ljava/lang/String;)V public fun setCodeFile (Ljava/lang/String;)V public fun setCodeId (Ljava/lang/String;)V @@ -2955,7 +3000,7 @@ public final class io/sentry/protocol/DebugMeta : io/sentry/JsonSerializable, io public fun getImages ()Ljava/util/List; public fun getSdkInfo ()Lio/sentry/protocol/SdkInfo; public fun getUnknown ()Ljava/util/Map; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setImages (Ljava/util/List;)V public fun setSdkInfo (Lio/sentry/protocol/SdkInfo;)V public fun setUnknown (Ljava/util/Map;)V @@ -3013,7 +3058,7 @@ public final class io/sentry/protocol/Device : io/sentry/JsonSerializable, io/se public fun isLowMemory ()Ljava/lang/Boolean; public fun isOnline ()Ljava/lang/Boolean; public fun isSimulator ()Ljava/lang/Boolean; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setArchs ([Ljava/lang/String;)V public fun setBatteryLevel (Ljava/lang/Float;)V public fun setBatteryTemperature (Ljava/lang/Float;)V @@ -3060,7 +3105,7 @@ public final class io/sentry/protocol/Device$Deserializer : io/sentry/JsonDeseri public final class io/sentry/protocol/Device$DeviceOrientation : java/lang/Enum, io/sentry/JsonSerializable { public static final field LANDSCAPE Lio/sentry/protocol/Device$DeviceOrientation; public static final field PORTRAIT Lio/sentry/protocol/Device$DeviceOrientation; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public static fun valueOf (Ljava/lang/String;)Lio/sentry/protocol/Device$DeviceOrientation; public static fun values ()[Lio/sentry/protocol/Device$DeviceOrientation; } @@ -3117,7 +3162,7 @@ public final class io/sentry/protocol/Geo : io/sentry/JsonSerializable, io/sentr public fun getCountryCode ()Ljava/lang/String; public fun getRegion ()Ljava/lang/String; public fun getUnknown ()Ljava/util/Map; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setCity (Ljava/lang/String;)V public fun setCountryCode (Ljava/lang/String;)V public fun setRegion (Ljava/lang/String;)V @@ -3152,7 +3197,7 @@ public final class io/sentry/protocol/Gpu : io/sentry/JsonSerializable, io/sentr public fun getVersion ()Ljava/lang/String; public fun hashCode ()I public fun isMultiThreadedRendering ()Ljava/lang/Boolean; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setApiType (Ljava/lang/String;)V public fun setId (Ljava/lang/Integer;)V public fun setMemorySize (Ljava/lang/Integer;)V @@ -3197,7 +3242,7 @@ public final class io/sentry/protocol/MeasurementValue : io/sentry/JsonSerializa public fun getUnit ()Ljava/lang/String; public fun getUnknown ()Ljava/util/Map; public fun getValue ()Ljava/lang/Number; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setUnknown (Ljava/util/Map;)V } @@ -3224,7 +3269,7 @@ public final class io/sentry/protocol/Mechanism : io/sentry/JsonSerializable, io public fun getType ()Ljava/lang/String; public fun getUnknown ()Ljava/util/Map; public fun isHandled ()Ljava/lang/Boolean; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setData (Ljava/util/Map;)V public fun setDescription (Ljava/lang/String;)V public fun setHandled (Ljava/lang/Boolean;)V @@ -3258,7 +3303,7 @@ public final class io/sentry/protocol/Message : io/sentry/JsonSerializable, io/s public fun getMessage ()Ljava/lang/String; public fun getParams ()Ljava/util/List; public fun getUnknown ()Ljava/util/Map; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setFormatted (Ljava/lang/String;)V public fun setMessage (Ljava/lang/String;)V public fun setParams (Ljava/util/List;)V @@ -3290,7 +3335,7 @@ public final class io/sentry/protocol/OperatingSystem : io/sentry/JsonSerializab public fun getVersion ()Ljava/lang/String; public fun hashCode ()I public fun isRooted ()Ljava/lang/Boolean; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setBuild (Ljava/lang/String;)V public fun setKernelVersion (Ljava/lang/String;)V public fun setName (Ljava/lang/String;)V @@ -3333,7 +3378,7 @@ public final class io/sentry/protocol/Request : io/sentry/JsonSerializable, io/s public fun getUnknown ()Ljava/util/Map; public fun getUrl ()Ljava/lang/String; public fun hashCode ()I - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setApiTarget (Ljava/lang/String;)V public fun setBodySize (Ljava/lang/Long;)V public fun setCookies (Ljava/lang/String;)V @@ -3379,7 +3424,7 @@ public final class io/sentry/protocol/Response : io/sentry/JsonSerializable, io/ public fun getHeaders ()Ljava/util/Map; public fun getStatusCode ()Ljava/lang/Integer; public fun getUnknown ()Ljava/util/Map; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setBodySize (Ljava/lang/Long;)V public fun setCookies (Ljava/lang/String;)V public fun setData (Ljava/lang/Object;)V @@ -3410,7 +3455,7 @@ public final class io/sentry/protocol/SdkInfo : io/sentry/JsonSerializable, io/s public fun getVersionMajor ()Ljava/lang/Integer; public fun getVersionMinor ()Ljava/lang/Integer; public fun getVersionPatchlevel ()Ljava/lang/Integer; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setSdkName (Ljava/lang/String;)V public fun setUnknown (Ljava/util/Map;)V public fun setVersionMajor (Ljava/lang/Integer;)V @@ -3445,7 +3490,7 @@ public final class io/sentry/protocol/SdkVersion : io/sentry/JsonSerializable, i public fun getUnknown ()Ljava/util/Map; public fun getVersion ()Ljava/lang/String; public fun hashCode ()I - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setName (Ljava/lang/String;)V public fun setUnknown (Ljava/util/Map;)V public fun setVersion (Ljava/lang/String;)V @@ -3475,7 +3520,7 @@ public final class io/sentry/protocol/SentryException : io/sentry/JsonSerializab public fun getType ()Ljava/lang/String; public fun getUnknown ()Ljava/util/Map; public fun getValue ()Ljava/lang/String; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setMechanism (Lio/sentry/protocol/Mechanism;)V public fun setModule (Ljava/lang/String;)V public fun setStacktrace (Lio/sentry/protocol/SentryStackTrace;)V @@ -3508,7 +3553,7 @@ public final class io/sentry/protocol/SentryId : io/sentry/JsonSerializable { public fun (Ljava/util/UUID;)V public fun equals (Ljava/lang/Object;)Z public fun hashCode ()I - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun toString ()Ljava/lang/String; } @@ -3525,7 +3570,7 @@ public final class io/sentry/protocol/SentryPackage : io/sentry/JsonSerializable public fun getUnknown ()Ljava/util/Map; public fun getVersion ()Ljava/lang/String; public fun hashCode ()I - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setName (Ljava/lang/String;)V public fun setUnknown (Ljava/util/Map;)V public fun setVersion (Ljava/lang/String;)V @@ -3550,7 +3595,7 @@ public final class io/sentry/protocol/SentryRuntime : io/sentry/JsonSerializable public fun getRawDescription ()Ljava/lang/String; public fun getUnknown ()Ljava/util/Map; public fun getVersion ()Ljava/lang/String; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setName (Ljava/lang/String;)V public fun setRawDescription (Ljava/lang/String;)V public fun setUnknown (Ljava/util/Map;)V @@ -3586,7 +3631,7 @@ public final class io/sentry/protocol/SentrySpan : io/sentry/JsonSerializable, i public fun getTraceId ()Lio/sentry/protocol/SentryId; public fun getUnknown ()Ljava/util/Map; public fun isFinished ()Z - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setUnknown (Ljava/util/Map;)V } @@ -3634,7 +3679,7 @@ public final class io/sentry/protocol/SentryStackFrame : io/sentry/JsonSerializa public fun getVars ()Ljava/util/Map; public fun isInApp ()Ljava/lang/Boolean; public fun isNative ()Ljava/lang/Boolean; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setAbsPath (Ljava/lang/String;)V public fun setColno (Ljava/lang/Integer;)V public fun setContextLine (Ljava/lang/String;)V @@ -3693,7 +3738,7 @@ public final class io/sentry/protocol/SentryStackTrace : io/sentry/JsonSerializa public fun getRegisters ()Ljava/util/Map; public fun getSnapshot ()Ljava/lang/Boolean; public fun getUnknown ()Ljava/util/Map; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setFrames (Ljava/util/List;)V public fun setRegisters (Ljava/util/Map;)V public fun setSnapshot (Ljava/lang/Boolean;)V @@ -3726,7 +3771,7 @@ public final class io/sentry/protocol/SentryThread : io/sentry/JsonSerializable, public fun isCurrent ()Ljava/lang/Boolean; public fun isDaemon ()Ljava/lang/Boolean; public fun isMain ()Ljava/lang/Boolean; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setCrashed (Ljava/lang/Boolean;)V public fun setCurrent (Ljava/lang/Boolean;)V public fun setDaemon (Ljava/lang/Boolean;)V @@ -3774,7 +3819,7 @@ public final class io/sentry/protocol/SentryTransaction : io/sentry/SentryBaseEv public fun getUnknown ()Ljava/util/Map; public fun isFinished ()Z public fun isSampled ()Z - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setUnknown (Ljava/util/Map;)V } @@ -3798,7 +3843,7 @@ public final class io/sentry/protocol/SentryTransaction$JsonKeys { public final class io/sentry/protocol/TransactionInfo : io/sentry/JsonSerializable, io/sentry/JsonUnknown { public fun (Ljava/lang/String;)V public fun getUnknown ()Ljava/util/Map; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setUnknown (Ljava/util/Map;)V } @@ -3841,7 +3886,7 @@ public final class io/sentry/protocol/User : io/sentry/JsonSerializable, io/sent public fun getUnknown ()Ljava/util/Map; public fun getUsername ()Ljava/lang/String; public fun hashCode ()I - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setData (Ljava/util/Map;)V public fun setEmail (Ljava/lang/String;)V public fun setGeo (Lio/sentry/protocol/Geo;)V @@ -3878,7 +3923,7 @@ public final class io/sentry/protocol/ViewHierarchy : io/sentry/JsonSerializable public fun getRenderingSystem ()Ljava/lang/String; public fun getUnknown ()Ljava/util/Map; public fun getWindows ()Ljava/util/List; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setUnknown (Ljava/util/Map;)V } @@ -3908,7 +3953,7 @@ public final class io/sentry/protocol/ViewHierarchyNode : io/sentry/JsonSerializ public fun getWidth ()Ljava/lang/Double; public fun getX ()Ljava/lang/Double; public fun getY ()Ljava/lang/Double; - public fun serialize (Lio/sentry/JsonObjectWriter;Lio/sentry/ILogger;)V + public fun serialize (Lio/sentry/ObjectWriter;Lio/sentry/ILogger;)V public fun setAlpha (Ljava/lang/Double;)V public fun setChildren (Ljava/util/List;)V public fun setHeight (Ljava/lang/Double;)V @@ -4111,6 +4156,36 @@ public final class io/sentry/util/LogUtils { public static fun logNotInstanceOf (Ljava/lang/Class;Ljava/lang/Object;Lio/sentry/ILogger;)V } +public final class io/sentry/util/MapObjectWriter : io/sentry/ObjectWriter { + public fun (Ljava/util/Map;)V + public synthetic fun beginArray ()Lio/sentry/ObjectWriter; + public fun beginArray ()Lio/sentry/util/MapObjectWriter; + public synthetic fun beginObject ()Lio/sentry/ObjectWriter; + public fun beginObject ()Lio/sentry/util/MapObjectWriter; + public synthetic fun endArray ()Lio/sentry/ObjectWriter; + public fun endArray ()Lio/sentry/util/MapObjectWriter; + public synthetic fun endObject ()Lio/sentry/ObjectWriter; + public fun endObject ()Lio/sentry/util/MapObjectWriter; + public synthetic fun name (Ljava/lang/String;)Lio/sentry/ObjectWriter; + public fun name (Ljava/lang/String;)Lio/sentry/util/MapObjectWriter; + public synthetic fun nullValue ()Lio/sentry/ObjectWriter; + public fun nullValue ()Lio/sentry/util/MapObjectWriter; + public synthetic fun value (D)Lio/sentry/ObjectWriter; + public fun value (D)Lio/sentry/util/MapObjectWriter; + public synthetic fun value (J)Lio/sentry/ObjectWriter; + public fun value (J)Lio/sentry/util/MapObjectWriter; + public synthetic fun value (Lio/sentry/ILogger;Ljava/lang/Object;)Lio/sentry/ObjectWriter; + public fun value (Lio/sentry/ILogger;Ljava/lang/Object;)Lio/sentry/util/MapObjectWriter; + public synthetic fun value (Ljava/lang/Boolean;)Lio/sentry/ObjectWriter; + public fun value (Ljava/lang/Boolean;)Lio/sentry/util/MapObjectWriter; + public synthetic fun value (Ljava/lang/Number;)Lio/sentry/ObjectWriter; + public fun value (Ljava/lang/Number;)Lio/sentry/util/MapObjectWriter; + public synthetic fun value (Ljava/lang/String;)Lio/sentry/ObjectWriter; + public fun value (Ljava/lang/String;)Lio/sentry/util/MapObjectWriter; + public synthetic fun value (Z)Lio/sentry/ObjectWriter; + public fun value (Z)Lio/sentry/util/MapObjectWriter; +} + public final class io/sentry/util/Objects { public static fun equals (Ljava/lang/Object;Ljava/lang/Object;)Z public static fun hash ([Ljava/lang/Object;)I diff --git a/sentry/src/main/java/io/sentry/Breadcrumb.java b/sentry/src/main/java/io/sentry/Breadcrumb.java index de48d0d3d78..4085d901a15 100644 --- a/sentry/src/main/java/io/sentry/Breadcrumb.java +++ b/sentry/src/main/java/io/sentry/Breadcrumb.java @@ -561,8 +561,7 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); writer.name(JsonKeys.TIMESTAMP).value(logger, timestamp); if (message != null) { diff --git a/sentry/src/main/java/io/sentry/JsonObjectSerializer.java b/sentry/src/main/java/io/sentry/JsonObjectSerializer.java index e51cffc92cc..629b3fc417b 100644 --- a/sentry/src/main/java/io/sentry/JsonObjectSerializer.java +++ b/sentry/src/main/java/io/sentry/JsonObjectSerializer.java @@ -33,7 +33,7 @@ public JsonObjectSerializer(int maxDepth) { } public void serialize( - @NotNull JsonObjectWriter writer, @NotNull ILogger logger, @Nullable Object object) + @NotNull ObjectWriter writer, @NotNull ILogger logger, @Nullable Object object) throws IOException { if (object == null) { writer.nullValue(); @@ -89,7 +89,7 @@ public void serialize( // Helper private void serializeDate( - @NotNull JsonObjectWriter writer, @NotNull ILogger logger, @NotNull Date date) + @NotNull ObjectWriter writer, @NotNull ILogger logger, @NotNull Date date) throws IOException { try { writer.value(DateUtils.getTimestamp(date)); @@ -100,7 +100,7 @@ private void serializeDate( } private void serializeTimeZone( - @NotNull JsonObjectWriter writer, @NotNull ILogger logger, @NotNull TimeZone timeZone) + @NotNull ObjectWriter writer, @NotNull ILogger logger, @NotNull TimeZone timeZone) throws IOException { try { writer.value(timeZone.getID()); @@ -111,7 +111,7 @@ private void serializeTimeZone( } private void serializeCollection( - @NotNull JsonObjectWriter writer, @NotNull ILogger logger, @NotNull Collection collection) + @NotNull ObjectWriter writer, @NotNull ILogger logger, @NotNull Collection collection) throws IOException { writer.beginArray(); for (Object object : collection) { @@ -121,7 +121,7 @@ private void serializeCollection( } private void serializeMap( - @NotNull JsonObjectWriter writer, @NotNull ILogger logger, @NotNull Map map) + @NotNull ObjectWriter writer, @NotNull ILogger logger, @NotNull Map map) throws IOException { writer.beginObject(); for (Object key : map.keySet()) { diff --git a/sentry/src/main/java/io/sentry/JsonObjectWriter.java b/sentry/src/main/java/io/sentry/JsonObjectWriter.java index 08d200b25e8..314a9013aa5 100644 --- a/sentry/src/main/java/io/sentry/JsonObjectWriter.java +++ b/sentry/src/main/java/io/sentry/JsonObjectWriter.java @@ -6,18 +6,85 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public final class JsonObjectWriter extends JsonWriter { +public final class JsonObjectWriter implements ObjectWriter { + private final JsonWriter jsonWriter; private final JsonObjectSerializer jsonObjectSerializer; public JsonObjectWriter(Writer out, int maxDepth) { - super(out); + jsonWriter = new JsonWriter(out); jsonObjectSerializer = new JsonObjectSerializer(maxDepth); } + @Override + public JsonObjectWriter beginArray() throws IOException { + jsonWriter.beginArray(); + return this; + } + + @Override + public JsonObjectWriter endArray() throws IOException { + jsonWriter.endArray(); + return this; + } + + @Override + public JsonObjectWriter beginObject() throws IOException { + jsonWriter.beginObject(); + return this; + } + + @Override + public JsonObjectWriter endObject() throws IOException { + jsonWriter.endObject(); + return this; + } + @Override public JsonObjectWriter name(String name) throws IOException { - super.name(name); + jsonWriter.name(name); + return this; + } + + @Override + public JsonObjectWriter value(String value) throws IOException { + jsonWriter.value(value); + return this; + } + + @Override + public JsonObjectWriter nullValue() throws IOException { + jsonWriter.nullValue(); + return this; + } + + @Override + public JsonObjectWriter value(boolean value) throws IOException { + jsonWriter.value(value); + return this; + } + + @Override + public JsonObjectWriter value(Boolean value) throws IOException { + jsonWriter.value(value); + return this; + } + + @Override + public JsonObjectWriter value(double value) throws IOException { + jsonWriter.value(value); + return this; + } + + @Override + public JsonObjectWriter value(long value) throws IOException { + jsonWriter.value(value); + return this; + } + + @Override + public JsonObjectWriter value(Number value) throws IOException { + jsonWriter.value(value); return this; } @@ -29,9 +96,14 @@ public JsonObjectWriter name(String name) throws IOException { * @param object Object to encode. May be null. * @return this writer. */ + @Override public JsonObjectWriter value(@NotNull ILogger logger, @Nullable Object object) throws IOException { jsonObjectSerializer.serialize(this, logger, object); return this; } + + public void setIndent(@NotNull final String indent) { + jsonWriter.setIndent(indent); + } } diff --git a/sentry/src/main/java/io/sentry/JsonSerializable.java b/sentry/src/main/java/io/sentry/JsonSerializable.java index f3ae2cc605e..7cbc093927b 100644 --- a/sentry/src/main/java/io/sentry/JsonSerializable.java +++ b/sentry/src/main/java/io/sentry/JsonSerializable.java @@ -4,5 +4,5 @@ import org.jetbrains.annotations.NotNull; public interface JsonSerializable { - void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) throws IOException; + void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException; } diff --git a/sentry/src/main/java/io/sentry/ObjectWriter.java b/sentry/src/main/java/io/sentry/ObjectWriter.java new file mode 100644 index 00000000000..bab6e507de8 --- /dev/null +++ b/sentry/src/main/java/io/sentry/ObjectWriter.java @@ -0,0 +1,33 @@ +package io.sentry; + +import java.io.IOException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public interface ObjectWriter { + ObjectWriter beginArray() throws IOException; + + ObjectWriter endArray() throws IOException; + + ObjectWriter beginObject() throws IOException; + + ObjectWriter endObject() throws IOException; + + ObjectWriter name(String name) throws IOException; + + ObjectWriter value(String value) throws IOException; + + ObjectWriter nullValue() throws IOException; + + ObjectWriter value(boolean value) throws IOException; + + ObjectWriter value(Boolean value) throws IOException; + + ObjectWriter value(double value) throws IOException; + + ObjectWriter value(long value) throws IOException; + + ObjectWriter value(Number value) throws IOException; + + ObjectWriter value(@NotNull ILogger logger, @Nullable Object object) throws IOException; +} diff --git a/sentry/src/main/java/io/sentry/ProfilingTraceData.java b/sentry/src/main/java/io/sentry/ProfilingTraceData.java index 09582a6f4fe..0502a07d737 100644 --- a/sentry/src/main/java/io/sentry/ProfilingTraceData.java +++ b/sentry/src/main/java/io/sentry/ProfilingTraceData.java @@ -385,7 +385,7 @@ public static final class JsonKeys { } @Override - public void serialize(final @NotNull JsonObjectWriter writer, final @NotNull ILogger logger) + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) throws IOException { writer.beginObject(); writer.name(JsonKeys.ANDROID_API_LEVEL).value(logger, androidApiLevel); diff --git a/sentry/src/main/java/io/sentry/ProfilingTransactionData.java b/sentry/src/main/java/io/sentry/ProfilingTransactionData.java index 3591fdd8286..7717ae481aa 100644 --- a/sentry/src/main/java/io/sentry/ProfilingTransactionData.java +++ b/sentry/src/main/java/io/sentry/ProfilingTransactionData.java @@ -144,8 +144,7 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); writer.name(JsonKeys.ID).value(logger, id); writer.name(JsonKeys.TRACE_ID).value(logger, traceId); diff --git a/sentry/src/main/java/io/sentry/Scope.java b/sentry/src/main/java/io/sentry/Scope.java index 997f93c05d7..265b9b8a301 100644 --- a/sentry/src/main/java/io/sentry/Scope.java +++ b/sentry/src/main/java/io/sentry/Scope.java @@ -794,6 +794,11 @@ public void withTransaction(final @NotNull IWithTransaction callback) { } } + @NotNull + SentryOptions getOptions() { + return options; + } + @ApiStatus.Internal public @Nullable Session getSession() { return session; diff --git a/sentry/src/main/java/io/sentry/ScopeUtil.java b/sentry/src/main/java/io/sentry/ScopeUtil.java new file mode 100644 index 00000000000..01e21625405 --- /dev/null +++ b/sentry/src/main/java/io/sentry/ScopeUtil.java @@ -0,0 +1,48 @@ +package io.sentry; + +import io.sentry.util.MapObjectWriter; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +@ApiStatus.Internal +public final class ScopeUtil { + + @NotNull + public static Map serialize(@Nullable Scope scope) { + final @NotNull Map data = new HashMap<>(); + if (scope == null) { + return data; + } + + final @NotNull SentryOptions options = scope.getOptions(); + final @NotNull ObjectWriter writer = new MapObjectWriter(data); + + try { + serialize(writer, options, "user", scope.getUser()); + serialize(writer, options, "contexts", scope.getContexts()); + serialize(writer, options, "tags", scope.getTags()); + serialize(writer, options, "extras", scope.getExtras()); + serialize(writer, options, "fingerprint", scope.getFingerprint()); + serialize(writer, options, "level", scope.getLevel()); + serialize(writer, options, "breadcrumbs", scope.getBreadcrumbs()); + } catch (Exception e) { + options.getLogger().log(SentryLevel.ERROR, "Could not serialize scope"); + } + + return data; + } + + private static void serialize( + @NotNull ObjectWriter writer, + @NotNull SentryOptions options, + @NotNull String name, + @Nullable Object data) + throws IOException { + writer.name(name); + writer.value(options.getLogger(), data); + } +} diff --git a/sentry/src/main/java/io/sentry/SentryBaseEvent.java b/sentry/src/main/java/io/sentry/SentryBaseEvent.java index ed0593f9a51..7e7babe8197 100644 --- a/sentry/src/main/java/io/sentry/SentryBaseEvent.java +++ b/sentry/src/main/java/io/sentry/SentryBaseEvent.java @@ -345,9 +345,7 @@ public static final class JsonKeys { public static final class Serializer { public void serialize( - @NotNull SentryBaseEvent baseEvent, - @NotNull JsonObjectWriter writer, - @NotNull ILogger logger) + @NotNull SentryBaseEvent baseEvent, @NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { if (baseEvent.eventId != null) { writer.name(JsonKeys.EVENT_ID).value(logger, baseEvent.eventId); diff --git a/sentry/src/main/java/io/sentry/SentryEnvelopeHeader.java b/sentry/src/main/java/io/sentry/SentryEnvelopeHeader.java index b788a6f1a5a..1c29aea2443 100644 --- a/sentry/src/main/java/io/sentry/SentryEnvelopeHeader.java +++ b/sentry/src/main/java/io/sentry/SentryEnvelopeHeader.java @@ -89,8 +89,7 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); if (eventId != null) { writer.name(JsonKeys.EVENT_ID).value(logger, eventId); diff --git a/sentry/src/main/java/io/sentry/SentryEnvelopeItemHeader.java b/sentry/src/main/java/io/sentry/SentryEnvelopeItemHeader.java index 285edf37e51..25ed2172e7e 100644 --- a/sentry/src/main/java/io/sentry/SentryEnvelopeItemHeader.java +++ b/sentry/src/main/java/io/sentry/SentryEnvelopeItemHeader.java @@ -103,8 +103,7 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); if (contentType != null) { writer.name(JsonKeys.CONTENT_TYPE).value(contentType); diff --git a/sentry/src/main/java/io/sentry/SentryEvent.java b/sentry/src/main/java/io/sentry/SentryEvent.java index 8eeea440282..2462f60593d 100644 --- a/sentry/src/main/java/io/sentry/SentryEvent.java +++ b/sentry/src/main/java/io/sentry/SentryEvent.java @@ -248,8 +248,7 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); writer.name(JsonKeys.TIMESTAMP).value(logger, timestamp); if (message != null) { diff --git a/sentry/src/main/java/io/sentry/SentryItemType.java b/sentry/src/main/java/io/sentry/SentryItemType.java index 04f62de3399..a097573ebf2 100644 --- a/sentry/src/main/java/io/sentry/SentryItemType.java +++ b/sentry/src/main/java/io/sentry/SentryItemType.java @@ -54,8 +54,7 @@ public String getItemType() { } @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.value(itemType); } diff --git a/sentry/src/main/java/io/sentry/SentryLevel.java b/sentry/src/main/java/io/sentry/SentryLevel.java index 065cc44cc52..cdaa72fc970 100644 --- a/sentry/src/main/java/io/sentry/SentryLevel.java +++ b/sentry/src/main/java/io/sentry/SentryLevel.java @@ -13,8 +13,7 @@ public enum SentryLevel implements JsonSerializable { FATAL; @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.value(name().toLowerCase(Locale.ROOT)); } diff --git a/sentry/src/main/java/io/sentry/SentryLockReason.java b/sentry/src/main/java/io/sentry/SentryLockReason.java index 607e461ee96..2c59176bd96 100644 --- a/sentry/src/main/java/io/sentry/SentryLockReason.java +++ b/sentry/src/main/java/io/sentry/SentryLockReason.java @@ -117,8 +117,7 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); writer.name(JsonKeys.TYPE).value(type); if (address != null) { diff --git a/sentry/src/main/java/io/sentry/Session.java b/sentry/src/main/java/io/sentry/Session.java index cfe437912c4..9f78aed53a3 100644 --- a/sentry/src/main/java/io/sentry/Session.java +++ b/sentry/src/main/java/io/sentry/Session.java @@ -357,8 +357,7 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); if (sessionId != null) { writer.name(JsonKeys.SID).value(sessionId.toString()); diff --git a/sentry/src/main/java/io/sentry/SpanContext.java b/sentry/src/main/java/io/sentry/SpanContext.java index 7b387a8fb28..81ffb826c54 100644 --- a/sentry/src/main/java/io/sentry/SpanContext.java +++ b/sentry/src/main/java/io/sentry/SpanContext.java @@ -231,8 +231,7 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); writer.name(JsonKeys.TRACE_ID); traceId.serialize(writer, logger); diff --git a/sentry/src/main/java/io/sentry/SpanId.java b/sentry/src/main/java/io/sentry/SpanId.java index 8764578887b..01aa62162e7 100644 --- a/sentry/src/main/java/io/sentry/SpanId.java +++ b/sentry/src/main/java/io/sentry/SpanId.java @@ -44,8 +44,7 @@ public String toString() { // JsonElementSerializer @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.value(value); } diff --git a/sentry/src/main/java/io/sentry/SpanStatus.java b/sentry/src/main/java/io/sentry/SpanStatus.java index d8a4377ee65..3fe24494d57 100644 --- a/sentry/src/main/java/io/sentry/SpanStatus.java +++ b/sentry/src/main/java/io/sentry/SpanStatus.java @@ -106,8 +106,7 @@ private boolean matches(int httpStatusCode) { // JsonSerializable @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.value(name().toLowerCase(Locale.ROOT)); } diff --git a/sentry/src/main/java/io/sentry/TraceContext.java b/sentry/src/main/java/io/sentry/TraceContext.java index 10564e9208c..88bf08905b8 100644 --- a/sentry/src/main/java/io/sentry/TraceContext.java +++ b/sentry/src/main/java/io/sentry/TraceContext.java @@ -193,8 +193,7 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); writer.name(TraceContext.JsonKeys.TRACE_ID).value(logger, traceId); writer.name(TraceContext.JsonKeys.PUBLIC_KEY).value(publicKey); diff --git a/sentry/src/main/java/io/sentry/UserFeedback.java b/sentry/src/main/java/io/sentry/UserFeedback.java index 5b7740e2048..71ea6e857ff 100644 --- a/sentry/src/main/java/io/sentry/UserFeedback.java +++ b/sentry/src/main/java/io/sentry/UserFeedback.java @@ -147,8 +147,7 @@ public void setUnknown(@Nullable Map unknown) { // JsonSerializable @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); writer.name(JsonKeys.EVENT_ID); eventId.serialize(writer, logger); diff --git a/sentry/src/main/java/io/sentry/clientreport/ClientReport.java b/sentry/src/main/java/io/sentry/clientreport/ClientReport.java index 0f58486e978..a9703bb183b 100644 --- a/sentry/src/main/java/io/sentry/clientreport/ClientReport.java +++ b/sentry/src/main/java/io/sentry/clientreport/ClientReport.java @@ -4,9 +4,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.SentryLevel; import io.sentry.vendor.gson.stream.JsonToken; import java.io.IOException; @@ -55,8 +55,7 @@ public void setUnknown(@Nullable Map unknown) { } @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); writer.name(JsonKeys.TIMESTAMP).value(DateUtils.getTimestamp(timestamp)); diff --git a/sentry/src/main/java/io/sentry/clientreport/DiscardedEvent.java b/sentry/src/main/java/io/sentry/clientreport/DiscardedEvent.java index 350843c1536..de5cc12a1c0 100644 --- a/sentry/src/main/java/io/sentry/clientreport/DiscardedEvent.java +++ b/sentry/src/main/java/io/sentry/clientreport/DiscardedEvent.java @@ -3,9 +3,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.SentryLevel; import io.sentry.vendor.gson.stream.JsonToken; import java.io.IOException; @@ -72,8 +72,7 @@ public void setUnknown(@Nullable Map unknown) { } @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); writer.name(JsonKeys.REASON).value(reason); diff --git a/sentry/src/main/java/io/sentry/profilemeasurements/ProfileMeasurement.java b/sentry/src/main/java/io/sentry/profilemeasurements/ProfileMeasurement.java index 3d5f2240d56..76a2ee18bd4 100644 --- a/sentry/src/main/java/io/sentry/profilemeasurements/ProfileMeasurement.java +++ b/sentry/src/main/java/io/sentry/profilemeasurements/ProfileMeasurement.java @@ -3,9 +3,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.util.Objects; import io.sentry.vendor.gson.stream.JsonToken; import java.io.IOException; @@ -72,7 +72,7 @@ public static final class JsonKeys { } @Override - public void serialize(final @NotNull JsonObjectWriter writer, final @NotNull ILogger logger) + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) throws IOException { writer.beginObject(); writer.name(JsonKeys.UNIT).value(logger, unit); diff --git a/sentry/src/main/java/io/sentry/profilemeasurements/ProfileMeasurementValue.java b/sentry/src/main/java/io/sentry/profilemeasurements/ProfileMeasurementValue.java index 0e5e83aac8c..9639ba892ff 100644 --- a/sentry/src/main/java/io/sentry/profilemeasurements/ProfileMeasurementValue.java +++ b/sentry/src/main/java/io/sentry/profilemeasurements/ProfileMeasurementValue.java @@ -3,9 +3,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.util.Objects; import io.sentry.vendor.gson.stream.JsonToken; import java.io.IOException; @@ -62,7 +62,7 @@ public static final class JsonKeys { } @Override - public void serialize(final @NotNull JsonObjectWriter writer, final @NotNull ILogger logger) + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) throws IOException { writer.beginObject(); writer.name(JsonKeys.VALUE).value(logger, value); diff --git a/sentry/src/main/java/io/sentry/protocol/App.java b/sentry/src/main/java/io/sentry/protocol/App.java index 4ace02b52e6..c221a60df28 100644 --- a/sentry/src/main/java/io/sentry/protocol/App.java +++ b/sentry/src/main/java/io/sentry/protocol/App.java @@ -3,9 +3,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.util.CollectionUtils; import io.sentry.util.Objects; import io.sentry.vendor.gson.stream.JsonToken; @@ -184,8 +184,7 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); if (appIdentifier != null) { writer.name(JsonKeys.APP_IDENTIFIER).value(appIdentifier); diff --git a/sentry/src/main/java/io/sentry/protocol/Browser.java b/sentry/src/main/java/io/sentry/protocol/Browser.java index 260ef1ec64a..136c9be2c9e 100644 --- a/sentry/src/main/java/io/sentry/protocol/Browser.java +++ b/sentry/src/main/java/io/sentry/protocol/Browser.java @@ -3,9 +3,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.util.CollectionUtils; import io.sentry.util.Objects; import io.sentry.vendor.gson.stream.JsonToken; @@ -81,8 +81,7 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); if (name != null) { writer.name(JsonKeys.NAME).value(name); diff --git a/sentry/src/main/java/io/sentry/protocol/Contexts.java b/sentry/src/main/java/io/sentry/protocol/Contexts.java index fe72ad0a376..ce0c3219d0c 100644 --- a/sentry/src/main/java/io/sentry/protocol/Contexts.java +++ b/sentry/src/main/java/io/sentry/protocol/Contexts.java @@ -3,8 +3,8 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; +import io.sentry.ObjectWriter; import io.sentry.SpanContext; import io.sentry.util.Objects; import io.sentry.vendor.gson.stream.JsonToken; @@ -122,7 +122,7 @@ public void setResponse(final @NotNull Response response) { // region json @Override - public void serialize(final @NotNull JsonObjectWriter writer, final @NotNull ILogger logger) + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) throws IOException { writer.beginObject(); // Serialize in alphabetical order to keep determinism. diff --git a/sentry/src/main/java/io/sentry/protocol/DebugImage.java b/sentry/src/main/java/io/sentry/protocol/DebugImage.java index 20d81143dbb..00321900f15 100644 --- a/sentry/src/main/java/io/sentry/protocol/DebugImage.java +++ b/sentry/src/main/java/io/sentry/protocol/DebugImage.java @@ -3,9 +3,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.vendor.gson.stream.JsonToken; import java.io.IOException; import java.util.HashMap; @@ -271,8 +271,7 @@ public void setUnknown(@Nullable Map unknown) { // JsonSerializable @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); if (uuid != null) { writer.name(JsonKeys.UUID).value(uuid); diff --git a/sentry/src/main/java/io/sentry/protocol/DebugMeta.java b/sentry/src/main/java/io/sentry/protocol/DebugMeta.java index af582cf3dae..b06a9a72439 100644 --- a/sentry/src/main/java/io/sentry/protocol/DebugMeta.java +++ b/sentry/src/main/java/io/sentry/protocol/DebugMeta.java @@ -3,9 +3,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.vendor.gson.stream.JsonToken; import java.io.IOException; import java.util.ArrayList; @@ -73,8 +73,7 @@ public void setUnknown(@Nullable Map unknown) { // JsonSerializable @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); if (sdkInfo != null) { writer.name(JsonKeys.SDK_INFO).value(logger, sdkInfo); diff --git a/sentry/src/main/java/io/sentry/protocol/Device.java b/sentry/src/main/java/io/sentry/protocol/Device.java index 46f12618883..88897f1d78e 100644 --- a/sentry/src/main/java/io/sentry/protocol/Device.java +++ b/sentry/src/main/java/io/sentry/protocol/Device.java @@ -3,9 +3,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.util.CollectionUtils; import io.sentry.util.Objects; import io.sentry.vendor.gson.stream.JsonToken; @@ -534,7 +534,7 @@ public enum DeviceOrientation implements JsonSerializable { // JsonElementSerializer @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.value(toString().toLowerCase(Locale.ROOT)); } @@ -590,8 +590,7 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); if (name != null) { writer.name(JsonKeys.NAME).value(name); diff --git a/sentry/src/main/java/io/sentry/protocol/Geo.java b/sentry/src/main/java/io/sentry/protocol/Geo.java index a4c85fb8241..90fd86954e5 100644 --- a/sentry/src/main/java/io/sentry/protocol/Geo.java +++ b/sentry/src/main/java/io/sentry/protocol/Geo.java @@ -3,9 +3,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.vendor.gson.stream.JsonToken; import java.io.IOException; import java.util.Map; @@ -136,7 +136,7 @@ public void setUnknown(@Nullable Map unknown) { } @Override - public void serialize(JsonObjectWriter writer, ILogger logger) throws IOException { + public void serialize(@NotNull ObjectWriter writer, ILogger logger) throws IOException { writer.beginObject(); if (city != null) { writer.name(JsonKeys.CITY).value(city); diff --git a/sentry/src/main/java/io/sentry/protocol/Gpu.java b/sentry/src/main/java/io/sentry/protocol/Gpu.java index b8a5a1e3bc2..e2a2a83577b 100644 --- a/sentry/src/main/java/io/sentry/protocol/Gpu.java +++ b/sentry/src/main/java/io/sentry/protocol/Gpu.java @@ -3,9 +3,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.util.CollectionUtils; import io.sentry.util.Objects; import io.sentry.vendor.gson.stream.JsonToken; @@ -176,8 +176,7 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); if (name != null) { writer.name(JsonKeys.NAME).value(name); diff --git a/sentry/src/main/java/io/sentry/protocol/MeasurementValue.java b/sentry/src/main/java/io/sentry/protocol/MeasurementValue.java index 60539f83e70..0aec89acc35 100644 --- a/sentry/src/main/java/io/sentry/protocol/MeasurementValue.java +++ b/sentry/src/main/java/io/sentry/protocol/MeasurementValue.java @@ -3,9 +3,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.SentryLevel; import io.sentry.vendor.gson.stream.JsonToken; import java.io.IOException; @@ -78,8 +78,7 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); writer.name(JsonKeys.VALUE).value(value); diff --git a/sentry/src/main/java/io/sentry/protocol/Mechanism.java b/sentry/src/main/java/io/sentry/protocol/Mechanism.java index e2002de1697..b72d2d7a54f 100644 --- a/sentry/src/main/java/io/sentry/protocol/Mechanism.java +++ b/sentry/src/main/java/io/sentry/protocol/Mechanism.java @@ -3,9 +3,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.util.CollectionUtils; import io.sentry.vendor.gson.stream.JsonToken; import java.io.IOException; @@ -167,8 +167,7 @@ public void setUnknown(@Nullable Map unknown) { // JsonSerializable @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); if (type != null) { writer.name(JsonKeys.TYPE).value(type); diff --git a/sentry/src/main/java/io/sentry/protocol/Message.java b/sentry/src/main/java/io/sentry/protocol/Message.java index ad9b49764a9..9ebd0ebeb84 100644 --- a/sentry/src/main/java/io/sentry/protocol/Message.java +++ b/sentry/src/main/java/io/sentry/protocol/Message.java @@ -3,9 +3,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.util.CollectionUtils; import io.sentry.vendor.gson.stream.JsonToken; import java.io.IOException; @@ -94,8 +94,7 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); if (formatted != null) { writer.name(JsonKeys.FORMATTED).value(formatted); diff --git a/sentry/src/main/java/io/sentry/protocol/OperatingSystem.java b/sentry/src/main/java/io/sentry/protocol/OperatingSystem.java index 6a8107aaa0e..e4eaea2608f 100644 --- a/sentry/src/main/java/io/sentry/protocol/OperatingSystem.java +++ b/sentry/src/main/java/io/sentry/protocol/OperatingSystem.java @@ -3,9 +3,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.util.CollectionUtils; import io.sentry.util.Objects; import io.sentry.vendor.gson.stream.JsonToken; @@ -134,8 +134,7 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); if (name != null) { writer.name(JsonKeys.NAME).value(name); diff --git a/sentry/src/main/java/io/sentry/protocol/Request.java b/sentry/src/main/java/io/sentry/protocol/Request.java index 8d5e0cda4b6..1a069937153 100644 --- a/sentry/src/main/java/io/sentry/protocol/Request.java +++ b/sentry/src/main/java/io/sentry/protocol/Request.java @@ -3,9 +3,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.util.CollectionUtils; import io.sentry.util.Objects; import io.sentry.vendor.gson.stream.JsonToken; @@ -277,8 +277,7 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); if (url != null) { writer.name(JsonKeys.URL).value(url); diff --git a/sentry/src/main/java/io/sentry/protocol/Response.java b/sentry/src/main/java/io/sentry/protocol/Response.java index dcfec08f46a..23a16c78f8c 100644 --- a/sentry/src/main/java/io/sentry/protocol/Response.java +++ b/sentry/src/main/java/io/sentry/protocol/Response.java @@ -3,9 +3,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.util.CollectionUtils; import io.sentry.vendor.gson.stream.JsonToken; import java.io.IOException; @@ -121,7 +121,7 @@ public static final class JsonKeys { } @Override - public void serialize(final @NotNull JsonObjectWriter writer, final @NotNull ILogger logger) + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) throws IOException { writer.beginObject(); diff --git a/sentry/src/main/java/io/sentry/protocol/SdkInfo.java b/sentry/src/main/java/io/sentry/protocol/SdkInfo.java index cb5ff593b76..49fe2df0798 100644 --- a/sentry/src/main/java/io/sentry/protocol/SdkInfo.java +++ b/sentry/src/main/java/io/sentry/protocol/SdkInfo.java @@ -3,9 +3,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.vendor.gson.stream.JsonToken; import java.io.IOException; import java.util.HashMap; @@ -88,8 +88,7 @@ public void setUnknown(@Nullable Map unknown) { // JsonSerializable @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); if (sdkName != null) { writer.name(JsonKeys.SDK_NAME).value(sdkName); diff --git a/sentry/src/main/java/io/sentry/protocol/SdkVersion.java b/sentry/src/main/java/io/sentry/protocol/SdkVersion.java index eaa0aa34c91..1122301e1ce 100644 --- a/sentry/src/main/java/io/sentry/protocol/SdkVersion.java +++ b/sentry/src/main/java/io/sentry/protocol/SdkVersion.java @@ -3,9 +3,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.SentryIntegrationPackageStorage; import io.sentry.SentryLevel; import io.sentry.util.Objects; @@ -197,8 +197,7 @@ public void setUnknown(@Nullable Map unknown) { // JsonSerializable @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); writer.name(JsonKeys.NAME).value(name); writer.name(JsonKeys.VERSION).value(version); diff --git a/sentry/src/main/java/io/sentry/protocol/SentryException.java b/sentry/src/main/java/io/sentry/protocol/SentryException.java index 88ba2149e87..28973334a81 100644 --- a/sentry/src/main/java/io/sentry/protocol/SentryException.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryException.java @@ -3,9 +3,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.vendor.gson.stream.JsonToken; import java.io.IOException; import java.util.HashMap; @@ -187,8 +187,7 @@ public void setUnknown(@Nullable Map unknown) { // JsonSerializable @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); if (type != null) { writer.name(JsonKeys.TYPE).value(type); diff --git a/sentry/src/main/java/io/sentry/protocol/SentryId.java b/sentry/src/main/java/io/sentry/protocol/SentryId.java index 3e4450536f6..c68a72ac064 100644 --- a/sentry/src/main/java/io/sentry/protocol/SentryId.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryId.java @@ -3,8 +3,8 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; +import io.sentry.ObjectWriter; import io.sentry.util.StringUtils; import java.io.IOException; import java.util.UUID; @@ -73,8 +73,7 @@ public int hashCode() { // JsonSerializable @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.value(toString()); } diff --git a/sentry/src/main/java/io/sentry/protocol/SentryPackage.java b/sentry/src/main/java/io/sentry/protocol/SentryPackage.java index a8ed584bd09..351ad171916 100644 --- a/sentry/src/main/java/io/sentry/protocol/SentryPackage.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryPackage.java @@ -3,9 +3,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.SentryLevel; import io.sentry.util.Objects; import io.sentry.vendor.gson.stream.JsonToken; @@ -82,8 +82,7 @@ public void setUnknown(@Nullable Map unknown) { // JsonSerializable @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); writer.name(JsonKeys.NAME).value(name); writer.name(JsonKeys.VERSION).value(version); diff --git a/sentry/src/main/java/io/sentry/protocol/SentryRuntime.java b/sentry/src/main/java/io/sentry/protocol/SentryRuntime.java index f8ceaf411ce..5b751a718c3 100644 --- a/sentry/src/main/java/io/sentry/protocol/SentryRuntime.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryRuntime.java @@ -3,9 +3,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.util.CollectionUtils; import io.sentry.vendor.gson.stream.JsonToken; import java.io.IOException; @@ -75,8 +75,7 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); if (name != null) { writer.name(JsonKeys.NAME).value(name); diff --git a/sentry/src/main/java/io/sentry/protocol/SentrySpan.java b/sentry/src/main/java/io/sentry/protocol/SentrySpan.java index e733cf7cac9..4e73c424954 100644 --- a/sentry/src/main/java/io/sentry/protocol/SentrySpan.java +++ b/sentry/src/main/java/io/sentry/protocol/SentrySpan.java @@ -4,9 +4,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.SentryLevel; import io.sentry.Span; import io.sentry.SpanId; @@ -149,8 +149,7 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); writer.name(JsonKeys.START_TIMESTAMP).value(logger, doubleToBigDecimal(startTimestamp)); if (timestamp != null) { diff --git a/sentry/src/main/java/io/sentry/protocol/SentryStackFrame.java b/sentry/src/main/java/io/sentry/protocol/SentryStackFrame.java index f11e91fd75c..a8186a8fb9f 100644 --- a/sentry/src/main/java/io/sentry/protocol/SentryStackFrame.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryStackFrame.java @@ -3,9 +3,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.SentryLockReason; import io.sentry.vendor.gson.stream.JsonToken; import java.io.IOException; @@ -331,8 +331,7 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); if (filename != null) { writer.name(JsonKeys.FILENAME).value(filename); diff --git a/sentry/src/main/java/io/sentry/protocol/SentryStackTrace.java b/sentry/src/main/java/io/sentry/protocol/SentryStackTrace.java index d4d222dba82..1bdb1c9d321 100644 --- a/sentry/src/main/java/io/sentry/protocol/SentryStackTrace.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryStackTrace.java @@ -3,9 +3,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.util.CollectionUtils; import io.sentry.vendor.gson.stream.JsonToken; import java.io.IOException; @@ -128,8 +128,7 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); if (frames != null) { writer.name(JsonKeys.FRAMES).value(logger, frames); diff --git a/sentry/src/main/java/io/sentry/protocol/SentryThread.java b/sentry/src/main/java/io/sentry/protocol/SentryThread.java index b3e1c7c6a66..3f33284cd8f 100644 --- a/sentry/src/main/java/io/sentry/protocol/SentryThread.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryThread.java @@ -3,9 +3,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.SentryLockReason; import io.sentry.vendor.gson.stream.JsonToken; import java.io.IOException; @@ -257,8 +257,7 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); if (id != null) { writer.name(JsonKeys.ID).value(id); diff --git a/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java b/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java index 34f40ade040..3d8beaa459f 100644 --- a/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java @@ -4,9 +4,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.SentryBaseEvent; import io.sentry.SentryTracer; import io.sentry.Span; @@ -181,8 +181,7 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); if (transaction != null) { writer.name(JsonKeys.TRANSACTION).value(transaction); diff --git a/sentry/src/main/java/io/sentry/protocol/TransactionInfo.java b/sentry/src/main/java/io/sentry/protocol/TransactionInfo.java index 976008e53c9..4e2f81f7c3f 100644 --- a/sentry/src/main/java/io/sentry/protocol/TransactionInfo.java +++ b/sentry/src/main/java/io/sentry/protocol/TransactionInfo.java @@ -3,9 +3,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.vendor.gson.stream.JsonToken; import java.io.IOException; import java.util.Map; @@ -31,8 +31,7 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); if (source != null) { writer.name(JsonKeys.SOURCE).value(logger, source); diff --git a/sentry/src/main/java/io/sentry/protocol/User.java b/sentry/src/main/java/io/sentry/protocol/User.java index a6ff46b4d0c..5620f0a1e66 100644 --- a/sentry/src/main/java/io/sentry/protocol/User.java +++ b/sentry/src/main/java/io/sentry/protocol/User.java @@ -3,9 +3,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.SentryLevel; import io.sentry.SentryOptions; import io.sentry.util.CollectionUtils; @@ -377,8 +377,7 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); if (email != null) { writer.name(JsonKeys.EMAIL).value(email); diff --git a/sentry/src/main/java/io/sentry/protocol/ViewHierarchy.java b/sentry/src/main/java/io/sentry/protocol/ViewHierarchy.java index 9a24ccc8352..b83748df386 100644 --- a/sentry/src/main/java/io/sentry/protocol/ViewHierarchy.java +++ b/sentry/src/main/java/io/sentry/protocol/ViewHierarchy.java @@ -3,9 +3,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.vendor.gson.stream.JsonToken; import java.io.IOException; import java.util.HashMap; @@ -42,8 +42,7 @@ public List getWindows() { } @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); if (renderingSystem != null) { writer.name(JsonKeys.RENDERING_SYSTEM).value(renderingSystem); diff --git a/sentry/src/main/java/io/sentry/protocol/ViewHierarchyNode.java b/sentry/src/main/java/io/sentry/protocol/ViewHierarchyNode.java index d751b27a801..e2b7f4fe52f 100644 --- a/sentry/src/main/java/io/sentry/protocol/ViewHierarchyNode.java +++ b/sentry/src/main/java/io/sentry/protocol/ViewHierarchyNode.java @@ -3,9 +3,9 @@ import io.sentry.ILogger; import io.sentry.JsonDeserializer; import io.sentry.JsonObjectReader; -import io.sentry.JsonObjectWriter; import io.sentry.JsonSerializable; import io.sentry.JsonUnknown; +import io.sentry.ObjectWriter; import io.sentry.vendor.gson.stream.JsonToken; import java.io.IOException; import java.util.HashMap; @@ -145,8 +145,7 @@ public List getChildren() { } @Override - public void serialize(@NotNull JsonObjectWriter writer, @NotNull ILogger logger) - throws IOException { + public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { writer.beginObject(); if (renderingSystem != null) { writer.name(JsonKeys.RENDERING_SYSTEM).value(renderingSystem); diff --git a/sentry/src/main/java/io/sentry/util/MapObjectWriter.java b/sentry/src/main/java/io/sentry/util/MapObjectWriter.java new file mode 100644 index 00000000000..9417841ea3d --- /dev/null +++ b/sentry/src/main/java/io/sentry/util/MapObjectWriter.java @@ -0,0 +1,236 @@ +package io.sentry.util; + +import static io.sentry.util.JsonSerializationUtils.atomicIntegerArrayToList; +import static io.sentry.util.JsonSerializationUtils.calendarToMap; + +import io.sentry.DateUtils; +import io.sentry.ILogger; +import io.sentry.JsonSerializable; +import io.sentry.ObjectWriter; +import io.sentry.SentryLevel; +import java.io.IOException; +import java.net.InetAddress; +import java.net.URI; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Collection; +import java.util.Currency; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.TimeZone; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicIntegerArray; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public final class MapObjectWriter implements ObjectWriter { + + final @NotNull Map root; + /** + * The stack for maintaining the hierarchy and structure Possible elements: Map<>: An Object + * List<>: Array of objects String: The key for the object on top + */ + final @NotNull ArrayDeque stack; + + public MapObjectWriter(final @NotNull Map root) { + this.root = root; + stack = new ArrayDeque<>(); + stack.addLast(root); + } + + @Override + public MapObjectWriter name(final @NotNull String name) throws IOException { + stack.add(name); + return this; + } + + @Override + public MapObjectWriter value(final @NotNull ILogger logger, final @Nullable Object object) + throws IOException { + if (object == null) { + nullValue(); + } else if (object instanceof Character) { + value(Character.toString((Character) object)); + } else if (object instanceof String) { + value((String) object); + } else if (object instanceof Boolean) { + value((boolean) object); + } else if (object instanceof Number) { + value((Number) object); + } else if (object instanceof Date) { + serializeDate(logger, (Date) object); + } else if (object instanceof TimeZone) { + serializeTimeZone(logger, (TimeZone) object); + } else if (object instanceof JsonSerializable) { + ((JsonSerializable) object).serialize(this, logger); + } else if (object instanceof Collection) { + serializeCollection(logger, (Collection) object); + } else if (object.getClass().isArray()) { + serializeCollection(logger, Arrays.asList((Object[]) object)); + } else if (object instanceof Map) { + serializeMap(logger, (Map) object); + } else if (object instanceof Locale) { + value(object.toString()); + } else if (object instanceof AtomicIntegerArray) { + serializeCollection(logger, atomicIntegerArrayToList((AtomicIntegerArray) object)); + } else if (object instanceof AtomicBoolean) { + value(((AtomicBoolean) object).get()); + } else if (object instanceof URI) { + value(object.toString()); + } else if (object instanceof InetAddress) { + value(object.toString()); + } else if (object instanceof UUID) { + value(object.toString()); + } else if (object instanceof Currency) { + value(object.toString()); + } else if (object instanceof Calendar) { + serializeMap(logger, calendarToMap((Calendar) object)); + } else if (object.getClass().isEnum()) { + value(object.toString()); + } else { + logger.log(SentryLevel.WARNING, "Failed serializing unknown object.", object); + } + return this; + } + + @Override + public MapObjectWriter beginArray() throws IOException { + stack.add(new ArrayList<>()); + return this; + } + + @Override + public MapObjectWriter endArray() throws IOException { + endObject(); + return this; + } + + @Override + public MapObjectWriter beginObject() throws IOException { + stack.addLast(new HashMap<>()); + return this; + } + + @Override + public MapObjectWriter endObject() throws IOException { + final Object value = stack.removeLast(); + postValue(value); + return this; + } + + @Override + public MapObjectWriter value(final @Nullable String value) throws IOException { + postValue(value); + return this; + } + + @Override + public MapObjectWriter nullValue() throws IOException { + postValue((Object) null); + return this; + } + + @Override + public MapObjectWriter value(final boolean value) throws IOException { + postValue(value); + return this; + } + + @Override + public MapObjectWriter value(final @Nullable Boolean value) throws IOException { + postValue(value); + return this; + } + + @Override + public MapObjectWriter value(final double value) throws IOException { + postValue(value); + return this; + } + + @Override + public MapObjectWriter value(final long value) throws IOException { + postValue(value); + return this; + } + + @Override + public MapObjectWriter value(final @Nullable Number value) throws IOException { + postValue(value); + return this; + } + + private void serializeDate(final @NotNull ILogger logger, final @NotNull Date date) + throws IOException { + try { + value(DateUtils.getTimestamp(date)); + } catch (Exception e) { + logger.log(SentryLevel.ERROR, "Error when serializing Date", e); + nullValue(); // Fallback to setting null when date is malformed. + } + } + + private void serializeTimeZone(final @NotNull ILogger logger, final @NotNull TimeZone timeZone) + throws IOException { + try { + value(timeZone.getID()); + } catch (Exception e) { + logger.log(SentryLevel.ERROR, "Error when serializing TimeZone", e); + nullValue(); // Fallback. + } + } + + private void serializeCollection( + final @NotNull ILogger logger, final @NotNull Collection collection) throws IOException { + beginArray(); + for (Object object : collection) { + value(logger, object); + } + endArray(); + } + + private void serializeMap(final @NotNull ILogger logger, final @NotNull Map map) + throws IOException { + beginObject(); + for (Object key : map.keySet()) { + if (key instanceof String) { + name((String) key); + value(logger, map.get(key)); + } + } + endObject(); + } + + @SuppressWarnings("unchecked") + private void postValue(@Nullable Object value) { + final Object topStackElement = stack.peekLast(); + if (topStackElement instanceof List) { + // if top stack element is an array, value is an element within the array + ((List) topStackElement).add(value); + } else if (topStackElement instanceof String) { + // if top stack element is a String, it's the key for the value + // -> add both (key, value) to underlying map + final String key = (String) stack.removeLast(); + peekObject().put(key, value); + } else { + throw new IllegalStateException("Invalid stack state, expected array or string on top"); + } + } + + @SuppressWarnings("unchecked") + private @NotNull Map peekObject() { + final @Nullable Object item = stack.peekLast(); + if (item == null) { + throw new IllegalStateException("Stack is empty."); + } else if ((item instanceof Map)) { + return (Map) item; + } + throw new IllegalStateException("Stack element is not a Map."); + } +} diff --git a/sentry/src/test/java/io/sentry/ScopeUtilTest.kt b/sentry/src/test/java/io/sentry/ScopeUtilTest.kt new file mode 100644 index 00000000000..abaecbdf954 --- /dev/null +++ b/sentry/src/test/java/io/sentry/ScopeUtilTest.kt @@ -0,0 +1,35 @@ +package io.sentry + +import io.sentry.protocol.App +import io.sentry.protocol.User +import kotlin.test.Test +import kotlin.test.assertTrue + +class ScopeUtilTest { + @Test + fun `serializing scopes correctly creates map`() { + val options = SentryOptions() + val scope = Scope(options) + + scope.user = User().apply { + name = "John" + } + scope.addBreadcrumb(Breadcrumb.ui("ui.click", "button_login")) + scope.contexts.setApp( + App().apply { + appName = "Example App" + } + ) + scope.setTag("variant", "yellow") + + val serializedScope = ScopeUtil.serialize(scope) + + assertTrue(serializedScope.containsKey("user")) + assertTrue(serializedScope.containsKey("contexts")) + assertTrue(serializedScope.containsKey("tags")) + assertTrue(serializedScope.containsKey("extras")) + assertTrue(serializedScope.containsKey("fingerprint")) + assertTrue(serializedScope.containsKey("level")) + assertTrue(serializedScope.containsKey("breadcrumbs")) + } +} diff --git a/sentry/src/test/java/io/sentry/protocol/SentryBaseEventSerializationTest.kt b/sentry/src/test/java/io/sentry/protocol/SentryBaseEventSerializationTest.kt index b0f8e429f69..49608a86643 100644 --- a/sentry/src/test/java/io/sentry/protocol/SentryBaseEventSerializationTest.kt +++ b/sentry/src/test/java/io/sentry/protocol/SentryBaseEventSerializationTest.kt @@ -3,8 +3,8 @@ package io.sentry.protocol import io.sentry.ILogger import io.sentry.JsonDeserializer import io.sentry.JsonObjectReader -import io.sentry.JsonObjectWriter import io.sentry.JsonSerializable +import io.sentry.ObjectWriter import io.sentry.SentryBaseEvent import io.sentry.vendor.gson.stream.JsonToken import org.junit.Test @@ -17,7 +17,7 @@ class SentryBaseEventSerializationTest { * Make subclass, as `SentryBaseEvent` initializers are protected. */ class Sut : SentryBaseEvent(), JsonSerializable { - override fun serialize(writer: JsonObjectWriter, logger: ILogger) { + override fun serialize(writer: ObjectWriter, logger: ILogger) { writer.beginObject() Serializer().serialize(this, writer, logger) writer.endObject() diff --git a/sentry/src/test/java/io/sentry/util/MapObjectWriterTest.kt b/sentry/src/test/java/io/sentry/util/MapObjectWriterTest.kt new file mode 100644 index 00000000000..ece43cf5641 --- /dev/null +++ b/sentry/src/test/java/io/sentry/util/MapObjectWriterTest.kt @@ -0,0 +1,168 @@ +package io.sentry.util + +import io.sentry.ILogger +import io.sentry.JsonSerializable +import io.sentry.NoOpLogger +import io.sentry.ObjectWriter +import java.math.BigDecimal +import java.net.Inet4Address +import java.net.URI +import java.util.Calendar +import java.util.Currency +import java.util.Date +import java.util.Locale +import java.util.TimeZone +import java.util.UUID +import java.util.concurrent.atomic.AtomicBoolean +import java.util.concurrent.atomic.AtomicIntegerArray +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFails +import kotlin.test.assertTrue + +class MapObjectWriterTest { + + enum class BasicEnum { + A + } + + class BasicSerializable : JsonSerializable { + override fun serialize(writer: ObjectWriter, logger: ILogger) { + writer.beginObject() + .name("key") + .value("value") + .endObject() + } + } + + @Test + fun `serializes data correctly`() { + val logger = NoOpLogger.getInstance() + + val data = mutableMapOf() + val writer = MapObjectWriter(data) + + writer.name("null").nullValue() + writer.name("int").value(1 as Int) + writer.name("boolean").value(true) + writer.name("long").value(Long.MAX_VALUE) + writer.name("double").value(Double.MAX_VALUE) + writer.name("number").value(BigDecimal(123)) + writer.name("date").value(logger, Date(0)) + writer.name("string").value("string") + + writer.name("TimeZone").value(logger, TimeZone.getTimeZone("Vienna")) + writer.name("JsonSerializable").value(logger, BasicSerializable()) + writer.name("Collection").value(logger, listOf("a", "b")) + writer.name("Arrays").value(logger, arrayOf("b", "c")) + writer.name("Map").value(logger, mapOf(kotlin.Pair("key", "value"))) + writer.name("Locale").value(logger, Locale.US) + writer.name("AtomicIntegerArray").value(logger, AtomicIntegerArray(intArrayOf(0, 1, 2))) + writer.name("AtomicBoolean").value(logger, AtomicBoolean(false)) + writer.name("URI").value(logger, URI.create("http://www.example.com")) + writer.name("InetAddress").value(logger, Inet4Address.getByName("1.1.1.1")) + writer.name("UUID").value(logger, UUID.fromString("00000000-1111-2222-3333-444444444444")) + writer.name("Currency").value(logger, Currency.getInstance("EUR")) + writer.name("Calendar").value(logger, Calendar.getInstance().apply { timeInMillis = 0 }) + writer.name("Enum").value(logger, BasicEnum.A) + + assertEquals(null, data["null"]) + assertEquals(1, data["int"]) + assertEquals(true, data["boolean"]) + assertEquals(Long.MAX_VALUE, data["long"]) + assertEquals(Double.MAX_VALUE, data["double"]) + assertEquals(BigDecimal(123), data["number"]) + assertEquals("1970-01-01T00:00:00.000Z", data["date"]) + assertEquals("string", data["string"]) + + assertEquals("GMT", data["TimeZone"]) + assertEquals( + mapOf( + kotlin.Pair("key", "value") + ), + data["JsonSerializable"] + ) + + assertEquals(listOf("a", "b"), data["Collection"]) + assertEquals(listOf("b", "c"), data["Arrays"]) + assertEquals(mapOf(kotlin.Pair("key", "value")), data["Map"]) + assertEquals("en_US", data["Locale"]) + assertEquals(listOf(0, 1, 2), data["AtomicIntegerArray"]) + assertEquals(false, data["AtomicBoolean"]) + assertEquals("http://www.example.com", data["URI"]) + assertEquals("/1.1.1.1", data["InetAddress"]) + assertEquals("00000000-1111-2222-3333-444444444444", data["UUID"]) + assertEquals("EUR", data["Currency"]) + assertEquals( + mapOf( + kotlin.Pair("month", 0), + kotlin.Pair("year", 1970), + kotlin.Pair("dayOfMonth", 1), + kotlin.Pair("hourOfDay", 1), + kotlin.Pair("minute", 0), + kotlin.Pair("second", 0) + ), + data["Calendar"] + ) + assertEquals("A", data["Enum"]) + } + + @Test + fun `serializes objects correctly`() { + val data = mutableMapOf() + val writer = MapObjectWriter(data) + + writer.name("object") + writer.beginObject() + writer.name("key") + writer.value("value") + writer.endObject() + + assertTrue(data.containsKey("object")) + assertEquals("value", (data["object"] as Map<*, *>)["key"]) + } + + @Test + fun `serializes nested arrays correctly`() { + val data = mutableMapOf() + val writer = MapObjectWriter(data) + + writer.name("array") + writer.beginArray() + + writer.beginArray() + writer.value("0") + writer.value("1") + writer.endArray() + + writer.value("2") + writer.endArray() + + assertTrue(data.containsKey("array")) + assertEquals(2, (data["array"] as List<*>).size) + assertEquals("0", ((data["array"] as List<*>)[0] as List<*>)[0]) + assertEquals("1", ((data["array"] as List<*>)[0] as List<*>)[1]) + assertEquals("2", (data["array"] as List<*>)[1]) + } + + @Test + fun `incorrect usage causes exception`() { + val data = mutableMapOf() + val writer = MapObjectWriter(data) + + assertFails { + // missing .beginObject() + writer.endObject() + } + + assertFails { + // missing .beginArray() + writer.endArray() + } + + assertFails { + // missing .name() + writer.value("value") + } + } +} From 8b1b62b30c4da1d1a9cb7331dfbf37882ad41a43 Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Wed, 5 Jul 2023 09:15:52 +0200 Subject: [PATCH 02/10] Move from ScopeUtil to InternalSentrySdk To better reflect how cocoa works and have a more central API for hybrid SDKs --- sentry/api/sentry.api | 10 ++-- .../java/io/sentry/InternalSentrySdk.java | 39 +++++++++++++++ sentry/src/main/java/io/sentry/ScopeUtil.java | 48 ------------------- ...peUtilTest.kt => InternalSentrySdkTest.kt} | 25 ++++++++-- 4 files changed, 66 insertions(+), 56 deletions(-) create mode 100644 sentry/src/main/java/io/sentry/InternalSentrySdk.java delete mode 100644 sentry/src/main/java/io/sentry/ScopeUtil.java rename sentry/src/test/java/io/sentry/{ScopeUtilTest.kt => InternalSentrySdkTest.kt} (52%) diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index 7d9c367575d..de8321a3f7f 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -655,6 +655,11 @@ public abstract interface class io/sentry/IntegrationName { public fun getIntegrationName ()Ljava/lang/String; } +public final class io/sentry/InternalSentrySdk { + public fun ()V + public static fun serializeScope (Lio/sentry/Scope;)Ljava/util/Map; +} + public final class io/sentry/IpAddressUtils { public static final field DEFAULT_IP_ADDRESS Ljava/lang/String; public static fun isDefault (Ljava/lang/String;)Z @@ -1212,11 +1217,6 @@ public abstract interface class io/sentry/ScopeCallback { public abstract fun run (Lio/sentry/Scope;)V } -public final class io/sentry/ScopeUtil { - public fun ()V - public static fun serialize (Lio/sentry/Scope;)Ljava/util/Map; -} - public final class io/sentry/SendCachedEnvelopeFireAndForgetIntegration : io/sentry/Integration { public fun (Lio/sentry/SendCachedEnvelopeFireAndForgetIntegration$SendFireAndForgetFactory;)V public final fun register (Lio/sentry/IHub;Lio/sentry/SentryOptions;)V diff --git a/sentry/src/main/java/io/sentry/InternalSentrySdk.java b/sentry/src/main/java/io/sentry/InternalSentrySdk.java new file mode 100644 index 00000000000..34b1540f9d9 --- /dev/null +++ b/sentry/src/main/java/io/sentry/InternalSentrySdk.java @@ -0,0 +1,39 @@ +package io.sentry; + +import io.sentry.util.MapObjectWriter; +import java.util.HashMap; +import java.util.Map; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +@ApiStatus.Internal +public final class InternalSentrySdk { + + @NotNull + public static Map serializeScope(@Nullable Scope scope) { + final @NotNull Map data = new HashMap<>(); + if (scope == null) { + return data; + } + + final @NotNull SentryOptions options = scope.getOptions(); + final @NotNull ILogger logger = options.getLogger(); + final @NotNull ObjectWriter writer = new MapObjectWriter(data); + + try { + writer.name("user").value(logger, scope.getUser()); + writer.name("contexts").value(logger, scope.getContexts()); + writer.name("tags").value(logger, scope.getTags()); + writer.name("extras").value(logger, scope.getExtras()); + writer.name("fingerprint").value(logger, scope.getFingerprint()); + writer.name("level").value(logger, scope.getLevel()); + writer.name("breadcrumbs").value(logger, scope.getBreadcrumbs()); + } catch (Exception e) { + options.getLogger().log(SentryLevel.ERROR, "Could not serialize scope.", e); + return new HashMap<>(); + } + + return data; + } +} diff --git a/sentry/src/main/java/io/sentry/ScopeUtil.java b/sentry/src/main/java/io/sentry/ScopeUtil.java deleted file mode 100644 index 01e21625405..00000000000 --- a/sentry/src/main/java/io/sentry/ScopeUtil.java +++ /dev/null @@ -1,48 +0,0 @@ -package io.sentry; - -import io.sentry.util.MapObjectWriter; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -@ApiStatus.Internal -public final class ScopeUtil { - - @NotNull - public static Map serialize(@Nullable Scope scope) { - final @NotNull Map data = new HashMap<>(); - if (scope == null) { - return data; - } - - final @NotNull SentryOptions options = scope.getOptions(); - final @NotNull ObjectWriter writer = new MapObjectWriter(data); - - try { - serialize(writer, options, "user", scope.getUser()); - serialize(writer, options, "contexts", scope.getContexts()); - serialize(writer, options, "tags", scope.getTags()); - serialize(writer, options, "extras", scope.getExtras()); - serialize(writer, options, "fingerprint", scope.getFingerprint()); - serialize(writer, options, "level", scope.getLevel()); - serialize(writer, options, "breadcrumbs", scope.getBreadcrumbs()); - } catch (Exception e) { - options.getLogger().log(SentryLevel.ERROR, "Could not serialize scope"); - } - - return data; - } - - private static void serialize( - @NotNull ObjectWriter writer, - @NotNull SentryOptions options, - @NotNull String name, - @Nullable Object data) - throws IOException { - writer.name(name); - writer.value(options.getLogger(), data); - } -} diff --git a/sentry/src/test/java/io/sentry/ScopeUtilTest.kt b/sentry/src/test/java/io/sentry/InternalSentrySdkTest.kt similarity index 52% rename from sentry/src/test/java/io/sentry/ScopeUtilTest.kt rename to sentry/src/test/java/io/sentry/InternalSentrySdkTest.kt index abaecbdf954..9100719d011 100644 --- a/sentry/src/test/java/io/sentry/ScopeUtilTest.kt +++ b/sentry/src/test/java/io/sentry/InternalSentrySdkTest.kt @@ -2,12 +2,14 @@ package io.sentry import io.sentry.protocol.App import io.sentry.protocol.User +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever import kotlin.test.Test import kotlin.test.assertTrue -class ScopeUtilTest { +class InternalSentrySdkTest { @Test - fun `serializing scopes correctly creates map`() { + fun `serializeScope correctly creates top level map`() { val options = SentryOptions() val scope = Scope(options) @@ -22,7 +24,7 @@ class ScopeUtilTest { ) scope.setTag("variant", "yellow") - val serializedScope = ScopeUtil.serialize(scope) + val serializedScope = InternalSentrySdk.serializeScope(scope) assertTrue(serializedScope.containsKey("user")) assertTrue(serializedScope.containsKey("contexts")) @@ -32,4 +34,21 @@ class ScopeUtilTest { assertTrue(serializedScope.containsKey("level")) assertTrue(serializedScope.containsKey("breadcrumbs")) } + + @Test + fun `serializeScope returns empty map in case scope is null`() { + val serializedScope = InternalSentrySdk.serializeScope(null) + assertTrue(serializedScope.isEmpty()) + } + + @Test + fun `serializeScope returns empty map in case scope serialization fails`() { + val scope = mock() + val options = SentryOptions() + whenever(scope.options).thenReturn(options) + whenever(scope.user).thenThrow(IllegalStateException("something is off")) + + val serializedScope = InternalSentrySdk.serializeScope(scope) + assertTrue(serializedScope.isEmpty()) + } } From 6e3df8aa3fa229b918b3adb8689d0c247d25d237 Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Wed, 5 Jul 2023 11:53:04 +0200 Subject: [PATCH 03/10] Fix test --- sentry/src/test/java/io/sentry/util/MapObjectWriterTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sentry/src/test/java/io/sentry/util/MapObjectWriterTest.kt b/sentry/src/test/java/io/sentry/util/MapObjectWriterTest.kt index ece43cf5641..6a3308f9fdd 100644 --- a/sentry/src/test/java/io/sentry/util/MapObjectWriterTest.kt +++ b/sentry/src/test/java/io/sentry/util/MapObjectWriterTest.kt @@ -63,7 +63,7 @@ class MapObjectWriterTest { writer.name("InetAddress").value(logger, Inet4Address.getByName("1.1.1.1")) writer.name("UUID").value(logger, UUID.fromString("00000000-1111-2222-3333-444444444444")) writer.name("Currency").value(logger, Currency.getInstance("EUR")) - writer.name("Calendar").value(logger, Calendar.getInstance().apply { timeInMillis = 0 }) + writer.name("Calendar").value(logger, Calendar.getInstance(TimeZone.getTimeZone("UTC")).apply { timeInMillis = 0 }) writer.name("Enum").value(logger, BasicEnum.A) assertEquals(null, data["null"]) @@ -98,7 +98,7 @@ class MapObjectWriterTest { kotlin.Pair("month", 0), kotlin.Pair("year", 1970), kotlin.Pair("dayOfMonth", 1), - kotlin.Pair("hourOfDay", 1), + kotlin.Pair("hourOfDay", 0), kotlin.Pair("minute", 0), kotlin.Pair("second", 0) ), From a461f7e125b65240004e6162b341f383ce2e1394 Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Mon, 10 Jul 2023 16:01:26 +0200 Subject: [PATCH 04/10] Extract device information from DefaultAndroidEventProcessor --- .../api/sentry-android-core.api | 23 + .../android/core/AnrV2EventProcessor.java | 7 +- .../io/sentry/android/core/ContextUtils.java | 51 +- .../core/DefaultAndroidEventProcessor.java | 561 +----------------- .../sentry/android/core/DeviceInfoUtil.java | 519 ++++++++++++++++ .../io/sentry/android/core/Installation.java | 2 +- .../android/core}/InternalSentrySdk.java | 28 +- .../android/core/ContextUtilsUnitTests.kt | 11 +- .../core/DefaultAndroidEventProcessorTest.kt | 29 +- .../sentry/android/core/DeviceInfoUtilTest.kt | 156 +++++ .../android/core/InternalSentrySdkTest.kt | 106 ++++ sentry/api/sentry.api | 8 +- sentry/src/main/java/io/sentry/Scope.java | 9 +- .../java/io/sentry/InternalSentrySdkTest.kt | 54 -- .../io/sentry/util/MapObjectWriterTest.kt | 5 +- 15 files changed, 920 insertions(+), 649 deletions(-) create mode 100644 sentry-android-core/src/main/java/io/sentry/android/core/DeviceInfoUtil.java rename {sentry/src/main/java/io/sentry => sentry-android-core/src/main/java/io/sentry/android/core}/InternalSentrySdk.java (53%) create mode 100644 sentry-android-core/src/test/java/io/sentry/android/core/DeviceInfoUtilTest.kt create mode 100644 sentry-android-core/src/test/java/io/sentry/android/core/InternalSentrySdkTest.kt delete mode 100644 sentry/src/test/java/io/sentry/InternalSentrySdkTest.kt diff --git a/sentry-android-core/api/sentry-android-core.api b/sentry-android-core/api/sentry-android-core.api index ccfe1950016..f1be1674040 100644 --- a/sentry-android-core/api/sentry-android-core.api +++ b/sentry-android-core/api/sentry-android-core.api @@ -128,6 +128,9 @@ public final class io/sentry/android/core/BuildInfoProvider { public fun isEmulator ()Ljava/lang/Boolean; } +public final class io/sentry/android/core/ContextUtils { +} + public class io/sentry/android/core/CurrentActivityHolder { public fun clearActivity ()V public fun getActivity ()Landroid/app/Activity; @@ -148,6 +151,16 @@ public final class io/sentry/android/core/CurrentActivityIntegration : android/a public fun register (Lio/sentry/IHub;Lio/sentry/SentryOptions;)V } +public class io/sentry/android/core/DeviceInfoUtil { + public fun (Landroid/content/Context;Lio/sentry/android/core/SentryAndroidOptions;)V + public fun collectDeviceInformation (ZZ)Lio/sentry/protocol/Device; + public static fun getInstance (Landroid/content/Context;Lio/sentry/android/core/SentryAndroidOptions;)Lio/sentry/android/core/DeviceInfoUtil; + public final fun getOperatingSystem ()Lio/sentry/protocol/OperatingSystem; + public fun getSideLoadedInfo ()Lio/sentry/android/core/ContextUtils$SideLoadedInfo; + public static fun resetInstance ()V + protected fun retrieveOperatingSystemInformation ()Lio/sentry/protocol/OperatingSystem; +} + public abstract class io/sentry/android/core/EnvelopeFileObserverIntegration : io/sentry/Integration, java/io/Closeable { public fun ()V public fun close ()V @@ -160,6 +173,16 @@ public abstract interface class io/sentry/android/core/IDebugImagesLoader { public abstract fun loadDebugImages ()Ljava/util/List; } +public final class io/sentry/android/core/Installation { + public static fun id (Landroid/content/Context;)Ljava/lang/String; +} + +public final class io/sentry/android/core/InternalSentrySdk { + public fun ()V + public static fun getCurrentScope ()Lio/sentry/Scope; + public static fun serializeScope (Landroid/content/Context;Lio/sentry/android/core/SentryAndroidOptions;Lio/sentry/Scope;)Ljava/util/Map; +} + public final class io/sentry/android/core/LoadClass { public fun ()V public fun isClassAvailable (Ljava/lang/String;Lio/sentry/ILogger;)Z diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/AnrV2EventProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/AnrV2EventProcessor.java index cdbbd12c6b5..a49fbe09423 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/AnrV2EventProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/AnrV2EventProcessor.java @@ -524,11 +524,12 @@ private void mergeUser(final @NotNull SentryBaseEvent event) { private void setSideLoadedInfo(final @NotNull SentryBaseEvent event) { try { - final Map sideLoadedInfo = - ContextUtils.getSideLoadedInfo(context, options.getLogger(), buildInfoProvider); + final ContextUtils.SideLoadedInfo sideLoadedInfo = + ContextUtils.retrieveSideLoadedInfo(context, options.getLogger(), buildInfoProvider); if (sideLoadedInfo != null) { - for (final Map.Entry entry : sideLoadedInfo.entrySet()) { + final @NotNull Map tags = sideLoadedInfo.asTags(); + for (Map.Entry entry : tags.entrySet()) { event.setTag(entry.getKey(), entry.getValue()); } } diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ContextUtils.java b/sentry-android-core/src/main/java/io/sentry/android/core/ContextUtils.java index d43dde9471c..94743382ec9 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/ContextUtils.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ContextUtils.java @@ -22,10 +22,39 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -final class ContextUtils { +@ApiStatus.Internal +public final class ContextUtils { + + static class SideLoadedInfo { + private final boolean isSideLoaded; + private final @Nullable String installerStore; + + public SideLoadedInfo(boolean isSideLoaded, @Nullable String installerStore) { + this.isSideLoaded = isSideLoaded; + this.installerStore = installerStore; + } + + public boolean isSideLoaded() { + return isSideLoaded; + } + + public @Nullable String getInstallerStore() { + return installerStore; + } + + public @NotNull Map asTags() { + final Map data = new HashMap<>(); + data.put("isSideLoaded", String.valueOf(isSideLoaded)); + if (installerStore != null) { + data.put("installerStore", installerStore); + } + return data; + } + } private ContextUtils() {} @@ -187,8 +216,8 @@ static boolean isForegroundImportance(final @NotNull Context context) { return defaultVersion; } - @SuppressWarnings("deprecation") - static @Nullable Map getSideLoadedInfo( + @SuppressWarnings({"deprecation"}) + static @Nullable SideLoadedInfo retrieveSideLoadedInfo( final @NotNull Context context, final @NotNull ILogger logger, final @NotNull BuildInfoProvider buildInfoProvider) { @@ -202,20 +231,10 @@ static boolean isForegroundImportance(final @NotNull Context context) { // getInstallSourceInfo requires INSTALL_PACKAGES permission which is only given to system // apps. + // if it's installed via adb, system apps or untrusted sources + // could be amazon, google play etc - or null in case of sideload final String installerPackageName = packageManager.getInstallerPackageName(packageName); - - final Map sideLoadedInfo = new HashMap<>(); - - if (installerPackageName != null) { - sideLoadedInfo.put("isSideLoaded", "false"); - // could be amazon, google play etc - sideLoadedInfo.put("installerStore", installerPackageName); - } else { - // if it's installed via adb, system apps or untrusted sources - sideLoadedInfo.put("isSideLoaded", "true"); - } - - return sideLoadedInfo; + return new SideLoadedInfo(installerPackageName == null, installerPackageName); } } catch (IllegalArgumentException e) { // it'll never be thrown as we are querying its own App's package. diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java index 8d88c6674ae..e2e635e1d13 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java @@ -1,22 +1,12 @@ package io.sentry.android.core; import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED; -import static android.os.BatteryManager.EXTRA_TEMPERATURE; import android.annotation.SuppressLint; -import android.app.ActivityManager; import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; -import android.os.BatteryManager; import android.os.Build; -import android.os.Environment; -import android.os.LocaleList; -import android.os.StatFs; -import android.os.SystemClock; -import android.util.DisplayMetrics; import io.sentry.DateUtils; import io.sentry.EventProcessor; import io.sentry.Hint; @@ -24,27 +14,16 @@ import io.sentry.SentryEvent; import io.sentry.SentryLevel; import io.sentry.android.core.internal.util.AndroidMainThreadChecker; -import io.sentry.android.core.internal.util.ConnectivityChecker; -import io.sentry.android.core.internal.util.CpuInfoUtils; -import io.sentry.android.core.internal.util.DeviceOrientations; -import io.sentry.android.core.internal.util.RootChecker; import io.sentry.protocol.App; -import io.sentry.protocol.Device; import io.sentry.protocol.OperatingSystem; import io.sentry.protocol.SentryThread; import io.sentry.protocol.SentryTransaction; import io.sentry.protocol.User; import io.sentry.util.HintUtils; import io.sentry.util.Objects; -import java.io.File; -import java.util.Calendar; -import java.util.Collections; -import java.util.Date; import java.util.HashMap; -import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.TimeZone; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; @@ -54,75 +33,30 @@ final class DefaultAndroidEventProcessor implements EventProcessor { - @TestOnly static final String ROOTED = "rooted"; - @TestOnly static final String KERNEL_VERSION = "kernelVersion"; - @TestOnly static final String EMULATOR = "emulator"; - @TestOnly static final String SIDE_LOADED = "sideLoaded"; - @TestOnly final Context context; - @TestOnly final Future> contextData; - private final @NotNull BuildInfoProvider buildInfoProvider; - private final @NotNull RootChecker rootChecker; private final @NotNull SentryAndroidOptions options; + private final @NotNull Future deviceInfoUtil; public DefaultAndroidEventProcessor( final @NotNull Context context, final @NotNull BuildInfoProvider buildInfoProvider, final @NotNull SentryAndroidOptions options) { - this( - context, - buildInfoProvider, - new RootChecker(context, buildInfoProvider, options.getLogger()), - options); - } - - DefaultAndroidEventProcessor( - final @NotNull Context context, - final @NotNull BuildInfoProvider buildInfoProvider, - final @NotNull RootChecker rootChecker, - final @NotNull SentryAndroidOptions options) { this.context = Objects.requireNonNull(context, "The application context is required."); this.buildInfoProvider = Objects.requireNonNull(buildInfoProvider, "The BuildInfoProvider is required."); - this.rootChecker = Objects.requireNonNull(rootChecker, "The RootChecker is required."); this.options = Objects.requireNonNull(options, "The options object is required."); - ExecutorService executorService = Executors.newSingleThreadExecutor(); // don't ref. to method reference, theres a bug on it - //noinspection Convert2MethodRef - contextData = executorService.submit(() -> loadContextData()); - // reading CPU info performs disk I/O, but it's result is cached, let's pre-cache it - executorService.submit(() -> CpuInfoUtils.getInstance().readMaxFrequencies()); - + // noinspection Convert2MethodRef + // some device info performs disk I/O, but it's result is cached, let's pre-cache it + final @NotNull ExecutorService executorService = Executors.newSingleThreadExecutor(); + this.deviceInfoUtil = + executorService.submit(() -> DeviceInfoUtil.getInstance(context, options)); executorService.shutdown(); } - private @NotNull Map loadContextData() { - Map map = new HashMap<>(); - - if (options.isEnableRootCheck()) { - map.put(ROOTED, rootChecker.isDeviceRooted()); - } - - final String kernelVersion = ContextUtils.getKernelVersion(options.getLogger()); - if (kernelVersion != null) { - map.put(KERNEL_VERSION, kernelVersion); - } - - // its not IO, but it has been cached in the old version as well - map.put(EMULATOR, buildInfoProvider.isEmulator()); - - final Map sideLoadedInfo = - ContextUtils.getSideLoadedInfo(context, options.getLogger(), buildInfoProvider); - if (sideLoadedInfo != null) { - map.put(SIDE_LOADED, sideLoadedInfo); - } - - return map; - } - @Override public @NotNull SentryEvent process(final @NotNull SentryEvent event, final @NotNull Hint hint) { final boolean applyScopeData = shouldApplyScopeData(event, hint); @@ -145,7 +79,6 @@ private void setCommons( final boolean applyScopeData) { mergeUser(event); setDevice(event, errorEvent, applyScopeData); - mergeOS(event); setSideLoadedInfo(event); } @@ -168,9 +101,9 @@ private void mergeUser(final @NotNull SentryBaseEvent event) { // userId should be set even if event is Cached as the userId is static and won't change anyway. final User user = event.getUser(); if (user == null) { - event.setUser(getDefaultUser()); + event.setUser(getDefaultUser(context)); } else if (user.getId() == null) { - user.setId(getDeviceId()); + user.setId(Installation.id(context)); } } @@ -179,16 +112,26 @@ private void setDevice( final boolean errorEvent, final boolean applyScopeData) { if (event.getContexts().getDevice() == null) { - event.getContexts().setDevice(getDevice(errorEvent, applyScopeData)); + try { + event + .getContexts() + .setDevice(deviceInfoUtil.get().collectDeviceInformation(errorEvent, applyScopeData)); + } catch (Throwable e) { + options.getLogger().log(SentryLevel.ERROR, "Failed to retrieve device info", e); + } + mergeOS(event); } } private void mergeOS(final @NotNull SentryBaseEvent event) { final OperatingSystem currentOS = event.getContexts().getOperatingSystem(); - final OperatingSystem androidOS = getOperatingSystem(); - - // make Android OS the main OS using the 'os' key - event.getContexts().setOperatingSystem(androidOS); + try { + final OperatingSystem androidOS = deviceInfoUtil.get().getOperatingSystem(); + // make Android OS the main OS using the 'os' key + event.getContexts().setOperatingSystem(androidOS); + } catch (Throwable e) { + options.getLogger().log(SentryLevel.ERROR, "Failed to retrieve os system", e); + } if (currentOS != null) { // add additional OS which was already part of the SentryEvent (eg Linux read from NDK) @@ -210,9 +153,7 @@ private void processNonCachedEvent( app = new App(); } setAppExtras(app, hint); - setPackageInfo(event, app); - event.getContexts().setApp(app); } @@ -269,436 +210,6 @@ private void setAppExtras(final @NotNull App app, final @NotNull Hint hint) { } } - @SuppressWarnings({"ObsoleteSdkInt", "NewApi"}) - private @NotNull Long getMemorySize(final @NotNull ActivityManager.MemoryInfo memInfo) { - if (buildInfoProvider.getSdkInfoVersion() >= Build.VERSION_CODES.JELLY_BEAN) { - return memInfo.totalMem; - } - // using Runtime as a fallback - return java.lang.Runtime.getRuntime().totalMemory(); // JVM in bytes too - } - - // we can get some inspiration here - // https://github.com/flutter/plugins/blob/master/packages/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/DeviceInfoPlugin.java - private @NotNull Device getDevice(final boolean errorEvent, final boolean applyScopeData) { - // TODO: missing usable memory - - Device device = new Device(); - if (options.isSendDefaultPii()) { - device.setName(ContextUtils.getDeviceName(context, buildInfoProvider)); - } - device.setManufacturer(Build.MANUFACTURER); - device.setBrand(Build.BRAND); - device.setFamily(ContextUtils.getFamily(options.getLogger())); - device.setModel(Build.MODEL); - device.setModelId(Build.ID); - device.setArchs(ContextUtils.getArchitectures(buildInfoProvider)); - - // setting such values require IO hence we don't run for transactions - if (errorEvent) { - if (options.isCollectAdditionalContext()) { - setDeviceIO(device, applyScopeData); - } - } - - device.setOrientation(getOrientation()); - - try { - Object emulator = contextData.get().get(EMULATOR); - if (emulator != null) { - device.setSimulator((Boolean) emulator); - } - } catch (Throwable e) { - options.getLogger().log(SentryLevel.ERROR, "Error getting emulator.", e); - } - - DisplayMetrics displayMetrics = ContextUtils.getDisplayMetrics(context, options.getLogger()); - if (displayMetrics != null) { - device.setScreenWidthPixels(displayMetrics.widthPixels); - device.setScreenHeightPixels(displayMetrics.heightPixels); - device.setScreenDensity(displayMetrics.density); - device.setScreenDpi(displayMetrics.densityDpi); - } - - device.setBootTime(getBootTime()); - device.setTimezone(getTimeZone()); - - if (device.getId() == null) { - device.setId(getDeviceId()); - } - - final Locale locale = Locale.getDefault(); - if (device.getLanguage() == null) { - device.setLanguage(locale.getLanguage()); - } - if (device.getLocale() == null) { - device.setLocale(locale.toString()); // eg en_US - } - - final @NotNull List cpuFrequencies = CpuInfoUtils.getInstance().readMaxFrequencies(); - if (!cpuFrequencies.isEmpty()) { - device.setProcessorFrequency(Collections.max(cpuFrequencies).doubleValue()); - device.setProcessorCount(cpuFrequencies.size()); - } - - return device; - } - - private void setDeviceIO(final @NotNull Device device, final boolean applyScopeData) { - final Intent batteryIntent = getBatteryIntent(); - if (batteryIntent != null) { - device.setBatteryLevel(getBatteryLevel(batteryIntent)); - device.setCharging(isCharging(batteryIntent)); - device.setBatteryTemperature(getBatteryTemperature(batteryIntent)); - } - - Boolean connected; - switch (ConnectivityChecker.getConnectionStatus(context, options.getLogger())) { - case NOT_CONNECTED: - connected = false; - break; - case CONNECTED: - connected = true; - break; - default: - connected = null; - } - device.setOnline(connected); - - final ActivityManager.MemoryInfo memInfo = - ContextUtils.getMemInfo(context, options.getLogger()); - if (memInfo != null) { - // in bytes - device.setMemorySize(getMemorySize(memInfo)); - if (applyScopeData) { - device.setFreeMemory(memInfo.availMem); - device.setLowMemory(memInfo.lowMemory); - } - // there are runtime.totalMemory() and runtime.freeMemory(), but I kept the same for - // compatibility - } - - // this way of getting the size of storage might be problematic for storages bigger than 2GB - // check the use of - // https://developer.android.com/reference/java/io/File.html#getFreeSpace%28%29 - final File internalStorageFile = context.getExternalFilesDir(null); - if (internalStorageFile != null) { - StatFs internalStorageStat = new StatFs(internalStorageFile.getPath()); - device.setStorageSize(getTotalInternalStorage(internalStorageStat)); - device.setFreeStorage(getUnusedInternalStorage(internalStorageStat)); - } - - final StatFs externalStorageStat = getExternalStorageStat(internalStorageFile); - if (externalStorageStat != null) { - device.setExternalStorageSize(getTotalExternalStorage(externalStorageStat)); - device.setExternalFreeStorage(getUnusedExternalStorage(externalStorageStat)); - } - - if (device.getConnectionType() == null) { - // wifi, ethernet or cellular, null if none - device.setConnectionType( - ConnectivityChecker.getConnectionType(context, options.getLogger(), buildInfoProvider)); - } - } - - @SuppressWarnings("NewApi") - private TimeZone getTimeZone() { - if (buildInfoProvider.getSdkInfoVersion() >= Build.VERSION_CODES.N) { - LocaleList locales = context.getResources().getConfiguration().getLocales(); - if (!locales.isEmpty()) { - Locale locale = locales.get(0); - return Calendar.getInstance(locale).getTimeZone(); - } - } - return Calendar.getInstance().getTimeZone(); - } - - @SuppressWarnings("JdkObsolete") - private @Nullable Date getBootTime() { - try { - // if user changes the clock, will give a wrong answer, consider ACTION_TIME_CHANGED. - // currentTimeMillis returns UTC already - return DateUtils.getDateTime(System.currentTimeMillis() - SystemClock.elapsedRealtime()); - } catch (IllegalArgumentException e) { - options.getLogger().log(SentryLevel.ERROR, e, "Error getting the device's boot time."); - } - return null; - } - - private @Nullable Intent getBatteryIntent() { - return context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); - } - - /** - * Get the device's current battery level (as a percentage of total). - * - * @return the device's current battery level (as a percentage of total), or null if unknown - */ - private @Nullable Float getBatteryLevel(final @NotNull Intent batteryIntent) { - try { - int level = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); - int scale = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, -1); - - if (level == -1 || scale == -1) { - return null; - } - - float percentMultiplier = 100.0f; - - return ((float) level / (float) scale) * percentMultiplier; - } catch (Throwable e) { - options.getLogger().log(SentryLevel.ERROR, "Error getting device battery level.", e); - return null; - } - } - - /** - * Checks whether or not the device is currently plugged in and charging, or null if unknown. - * - * @return whether or not the device is currently plugged in and charging, or null if unknown - */ - private @Nullable Boolean isCharging(final @NotNull Intent batteryIntent) { - try { - int plugged = batteryIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); - return plugged == BatteryManager.BATTERY_PLUGGED_AC - || plugged == BatteryManager.BATTERY_PLUGGED_USB; - } catch (Throwable e) { - options.getLogger().log(SentryLevel.ERROR, "Error getting device charging state.", e); - return null; - } - } - - private @Nullable Float getBatteryTemperature(final @NotNull Intent batteryIntent) { - try { - int temperature = batteryIntent.getIntExtra(EXTRA_TEMPERATURE, -1); - if (temperature != -1) { - return ((float) temperature) / 10; // celsius - } - } catch (Throwable e) { - options.getLogger().log(SentryLevel.ERROR, "Error getting battery temperature.", e); - } - return null; - } - - /** - * Get the device's current screen orientation. - * - * @return the device's current screen orientation, or null if unknown - */ - @SuppressWarnings("deprecation") - private @Nullable Device.DeviceOrientation getOrientation() { - Device.DeviceOrientation deviceOrientation = null; - try { - deviceOrientation = - DeviceOrientations.getOrientation(context.getResources().getConfiguration().orientation); - if (deviceOrientation == null) { - options - .getLogger() - .log( - SentryLevel.INFO, - "No device orientation available (ORIENTATION_SQUARE|ORIENTATION_UNDEFINED)"); - return null; - } - } catch (Throwable e) { - options.getLogger().log(SentryLevel.ERROR, "Error getting device orientation.", e); - } - return deviceOrientation; - } - - /** - * Get the total amount of internal storage, in bytes. - * - * @return the total amount of internal storage, in bytes - */ - private @Nullable Long getTotalInternalStorage(final @NotNull StatFs stat) { - try { - long blockSize = getBlockSizeLong(stat); - long totalBlocks = getBlockCountLong(stat); - return totalBlocks * blockSize; - } catch (Throwable e) { - options.getLogger().log(SentryLevel.ERROR, "Error getting total internal storage amount.", e); - return null; - } - } - - @SuppressWarnings({"ObsoleteSdkInt", "NewApi"}) - private long getBlockSizeLong(final @NotNull StatFs stat) { - if (buildInfoProvider.getSdkInfoVersion() >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - return stat.getBlockSizeLong(); - } - return getBlockSizeDep(stat); - } - - @SuppressWarnings("deprecation") - private int getBlockSizeDep(final @NotNull StatFs stat) { - return stat.getBlockSize(); - } - - @SuppressWarnings({"ObsoleteSdkInt", "NewApi"}) - private long getBlockCountLong(final @NotNull StatFs stat) { - if (buildInfoProvider.getSdkInfoVersion() >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - return stat.getBlockCountLong(); - } - return getBlockCountDep(stat); - } - - @SuppressWarnings("deprecation") - private int getBlockCountDep(final @NotNull StatFs stat) { - return stat.getBlockCount(); - } - - @SuppressWarnings({"ObsoleteSdkInt", "NewApi"}) - private long getAvailableBlocksLong(final @NotNull StatFs stat) { - if (buildInfoProvider.getSdkInfoVersion() >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - return stat.getAvailableBlocksLong(); - } - return getAvailableBlocksDep(stat); - } - - @SuppressWarnings("deprecation") - private int getAvailableBlocksDep(final @NotNull StatFs stat) { - return stat.getAvailableBlocks(); - } - - /** - * Get the unused amount of internal storage, in bytes. - * - * @return the unused amount of internal storage, in bytes - */ - private @Nullable Long getUnusedInternalStorage(final @NotNull StatFs stat) { - try { - long blockSize = getBlockSizeLong(stat); - long availableBlocks = getAvailableBlocksLong(stat); - return availableBlocks * blockSize; - } catch (Throwable e) { - options - .getLogger() - .log(SentryLevel.ERROR, "Error getting unused internal storage amount.", e); - return null; - } - } - - private @Nullable StatFs getExternalStorageStat(final @Nullable File internalStorage) { - if (!isExternalStorageMounted()) { - File path = getExternalStorageDep(internalStorage); - if (path != null) { // && path.canRead()) { canRead() will read return false - return new StatFs(path.getPath()); - } - options.getLogger().log(SentryLevel.INFO, "Not possible to read external files directory"); - return null; - } - options.getLogger().log(SentryLevel.INFO, "External storage is not mounted or emulated."); - return null; - } - - @SuppressWarnings({"ObsoleteSdkInt", "NewApi"}) - private @Nullable File[] getExternalFilesDirs() { - if (buildInfoProvider.getSdkInfoVersion() >= Build.VERSION_CODES.KITKAT) { - return context.getExternalFilesDirs(null); - } else { - File single = context.getExternalFilesDir(null); - if (single != null) { - return new File[] {single}; - } - } - return null; - } - - private @Nullable File getExternalStorageDep(final @Nullable File internalStorage) { - File[] externalFilesDirs = getExternalFilesDirs(); - - if (externalFilesDirs != null) { - // return the 1st file which is not the emulated internal storage - String internalStoragePath = - internalStorage != null ? internalStorage.getAbsolutePath() : null; - for (File file : externalFilesDirs) { - // externalFilesDirs may contain null values :( - if (file == null) { - continue; - } - - // return the 1st file if you cannot compare with the internal one - if (internalStoragePath == null || internalStoragePath.isEmpty()) { - return file; - } - // if we are looking to the same directory, let's check the next one or no external storage - if (file.getAbsolutePath().contains(internalStoragePath)) { - continue; - } - return file; - } - } else { - options.getLogger().log(SentryLevel.INFO, "Not possible to read getExternalFilesDirs"); - } - return null; - } - - /** - * Get the total amount of external storage, in bytes, or null if no external storage is mounted. - * - * @return the total amount of external storage, in bytes, or null if no external storage is - * mounted - */ - private @Nullable Long getTotalExternalStorage(final @NotNull StatFs stat) { - try { - long blockSize = getBlockSizeLong(stat); - long totalBlocks = getBlockCountLong(stat); - return totalBlocks * blockSize; - } catch (Throwable e) { - options.getLogger().log(SentryLevel.ERROR, "Error getting total external storage amount.", e); - return null; - } - } - - private boolean isExternalStorageMounted() { - final String storageState = Environment.getExternalStorageState(); - return (Environment.MEDIA_MOUNTED.equals(storageState) - || Environment.MEDIA_MOUNTED_READ_ONLY.equals(storageState)) - && !Environment.isExternalStorageEmulated(); - } - - /** - * Get the unused amount of external storage, in bytes, or null if no external storage is mounted. - * - * @return the unused amount of external storage, in bytes, or null if no external storage is - * mounted - */ - private @Nullable Long getUnusedExternalStorage(final @NotNull StatFs stat) { - try { - long blockSize = getBlockSizeLong(stat); - long availableBlocks = getAvailableBlocksLong(stat); - return availableBlocks * blockSize; - } catch (Throwable e) { - options - .getLogger() - .log(SentryLevel.ERROR, "Error getting unused external storage amount.", e); - return null; - } - } - - private @NotNull OperatingSystem getOperatingSystem() { - OperatingSystem os = new OperatingSystem(); - os.setName("Android"); - os.setVersion(Build.VERSION.RELEASE); - os.setBuild(Build.DISPLAY); - - try { - Object kernelVersion = contextData.get().get(KERNEL_VERSION); - if (kernelVersion != null) { - os.setKernelVersion((String) kernelVersion); - } - - Object rooted = contextData.get().get(ROOTED); - if (rooted != null) { - os.setRooted((Boolean) rooted); - } - } catch (Throwable e) { - options.getLogger().log(SentryLevel.ERROR, "Error getting OperatingSystem.", e); - } - - return os; - } - @SuppressLint("NewApi") // we perform an if-check for that, but lint fails to recognize private void setAppPackageInfo(final @NotNull App app, final @NotNull PackageInfo packageInfo) { app.setAppIdentifier(packageInfo.packageName); @@ -733,30 +244,18 @@ private void setAppPackageInfo(final @NotNull App app, final @NotNull PackageInf * * @return the User object */ - public @NotNull User getDefaultUser() { - User user = new User(); - user.setId(getDeviceId()); - + public @NotNull User getDefaultUser(final @NotNull Context context) { + final @NotNull User user = new User(); + user.setId(Installation.id(context)); return user; } - private @Nullable String getDeviceId() { - try { - return Installation.id(context); - } catch (Throwable e) { - options.getLogger().log(SentryLevel.ERROR, "Error getting installationId.", e); - } - return null; - } - - @SuppressWarnings("unchecked") private void setSideLoadedInfo(final @NotNull SentryBaseEvent event) { try { - final Object sideLoadedInfo = contextData.get().get(SIDE_LOADED); - - if (sideLoadedInfo instanceof Map) { - for (final Map.Entry entry : - ((Map) sideLoadedInfo).entrySet()) { + final ContextUtils.SideLoadedInfo sideLoadedInfo = deviceInfoUtil.get().getSideLoadedInfo(); + if (sideLoadedInfo != null) { + final @NotNull Map tags = sideLoadedInfo.asTags(); + for (Map.Entry entry : tags.entrySet()) { event.setTag(entry.getKey(), entry.getValue()); } } diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/DeviceInfoUtil.java b/sentry-android-core/src/main/java/io/sentry/android/core/DeviceInfoUtil.java new file mode 100644 index 00000000000..f9f9d40e791 --- /dev/null +++ b/sentry-android-core/src/main/java/io/sentry/android/core/DeviceInfoUtil.java @@ -0,0 +1,519 @@ +package io.sentry.android.core; + +import static android.os.BatteryManager.EXTRA_TEMPERATURE; + +import android.annotation.SuppressLint; +import android.app.ActivityManager; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.BatteryManager; +import android.os.Build; +import android.os.Environment; +import android.os.LocaleList; +import android.os.StatFs; +import android.os.SystemClock; +import android.util.DisplayMetrics; +import io.sentry.DateUtils; +import io.sentry.SentryLevel; +import io.sentry.android.core.internal.util.ConnectivityChecker; +import io.sentry.android.core.internal.util.CpuInfoUtils; +import io.sentry.android.core.internal.util.DeviceOrientations; +import io.sentry.android.core.internal.util.RootChecker; +import io.sentry.protocol.Device; +import io.sentry.protocol.OperatingSystem; +import java.io.File; +import java.util.Calendar; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.TimeZone; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; + +@ApiStatus.Internal +public class DeviceInfoUtil { + + @SuppressLint("StaticFieldLeak") + private static volatile DeviceInfoUtil instance; + + private final @NotNull Context context; + private final @NotNull SentryAndroidOptions options; + private final @NotNull BuildInfoProvider buildInfoProvider; + private final @Nullable Boolean isEmulator; + private final @Nullable ContextUtils.SideLoadedInfo sideLoadedInfo; + private final @NotNull OperatingSystem os; + + public DeviceInfoUtil( + final @NotNull Context context, final @NotNull SentryAndroidOptions options) { + this.context = context; + this.options = options; + this.buildInfoProvider = new BuildInfoProvider(options.getLogger()); + + // these are potentially expense IO operations + CpuInfoUtils.getInstance().readMaxFrequencies(); + os = retrieveOperatingSystemInformation(); + isEmulator = buildInfoProvider.isEmulator(); + sideLoadedInfo = + ContextUtils.retrieveSideLoadedInfo(context, options.getLogger(), buildInfoProvider); + } + + public static @NotNull DeviceInfoUtil getInstance( + final @NotNull Context context, final @NotNull SentryAndroidOptions options) { + if (instance == null) { + synchronized (DeviceInfoUtil.class) { + if (instance == null) { + instance = new DeviceInfoUtil(context.getApplicationContext(), options); + } + } + } + return instance; + } + + @TestOnly + public static void resetInstance() { + instance = null; + } + + // we can get some inspiration here + // https://github.com/flutter/plugins/blob/master/packages/device_info/android/src/main/java/io/flutter/plugins/deviceinfo/DeviceInfoPlugin.java + @NotNull + public Device collectDeviceInformation( + final boolean collectDeviceIO, final boolean collectDynamicData) { + // TODO: missing usable memory + final @NotNull Device device = new Device(); + + if (options.isSendDefaultPii()) { + device.setName(ContextUtils.getDeviceName(context, buildInfoProvider)); + } + device.setManufacturer(Build.MANUFACTURER); + device.setBrand(Build.BRAND); + device.setFamily(ContextUtils.getFamily(options.getLogger())); + device.setModel(Build.MODEL); + device.setModelId(Build.ID); + device.setArchs(ContextUtils.getArchitectures(buildInfoProvider)); + + device.setOrientation(getOrientation()); + if (isEmulator != null) { + device.setSimulator(isEmulator); + } + + final @Nullable DisplayMetrics displayMetrics = + ContextUtils.getDisplayMetrics(context, options.getLogger()); + if (displayMetrics != null) { + device.setScreenWidthPixels(displayMetrics.widthPixels); + device.setScreenHeightPixels(displayMetrics.heightPixels); + device.setScreenDensity(displayMetrics.density); + device.setScreenDpi(displayMetrics.densityDpi); + } + + device.setBootTime(getBootTime()); + device.setTimezone(getTimeZone()); + + if (device.getId() == null) { + device.setId(getDeviceId()); + } + + final @NotNull Locale locale = Locale.getDefault(); + if (device.getLanguage() == null) { + device.setLanguage(locale.getLanguage()); + } + if (device.getLocale() == null) { + device.setLocale(locale.toString()); // eg en_US + } + + final @NotNull List cpuFrequencies = CpuInfoUtils.getInstance().readMaxFrequencies(); + if (!cpuFrequencies.isEmpty()) { + device.setProcessorFrequency(Collections.max(cpuFrequencies).doubleValue()); + device.setProcessorCount(cpuFrequencies.size()); + } + + // setting such values require IO hence we don't run for transactions + if (collectDeviceIO && options.isCollectAdditionalContext()) { + setDeviceIO(device, collectDynamicData); + } + + return device; + } + + public final @NotNull OperatingSystem getOperatingSystem() { + return os; + } + + @NotNull + protected OperatingSystem retrieveOperatingSystemInformation() { + + final OperatingSystem os = new OperatingSystem(); + os.setName("Android"); + os.setVersion(Build.VERSION.RELEASE); + os.setBuild(Build.DISPLAY); + + final @Nullable String kernelVersion = ContextUtils.getKernelVersion(options.getLogger()); + if (kernelVersion != null) { + os.setKernelVersion(kernelVersion); + } + + if (options.isEnableRootCheck()) { + final boolean rooted = + new RootChecker(context, buildInfoProvider, options.getLogger()).isDeviceRooted(); + os.setRooted(rooted); + } + return os; + } + + public @Nullable ContextUtils.SideLoadedInfo getSideLoadedInfo() { + return sideLoadedInfo; + } + + private void setDeviceIO(final @NotNull Device device, final boolean includeDynamicData) { + final Intent batteryIntent = getBatteryIntent(); + if (batteryIntent != null) { + device.setBatteryLevel(getBatteryLevel(batteryIntent)); + device.setCharging(isCharging(batteryIntent)); + device.setBatteryTemperature(getBatteryTemperature(batteryIntent)); + } + + Boolean connected; + switch (ConnectivityChecker.getConnectionStatus(context, options.getLogger())) { + case NOT_CONNECTED: + connected = false; + break; + case CONNECTED: + connected = true; + break; + default: + connected = null; + } + device.setOnline(connected); + + final @Nullable ActivityManager.MemoryInfo memInfo = + ContextUtils.getMemInfo(context, options.getLogger()); + if (memInfo != null) { + // in bytes + device.setMemorySize(getMemorySize(memInfo)); + if (includeDynamicData) { + device.setFreeMemory(memInfo.availMem); + device.setLowMemory(memInfo.lowMemory); + } + // there are runtime.totalMemory() and runtime.freeMemory(), but I kept the same for + // compatibility + } + + // this way of getting the size of storage might be problematic for storages bigger than 2GB + // check the use of + // https://developer.android.com/reference/java/io/File.html#getFreeSpace%28%29 + final @Nullable File internalStorageFile = context.getExternalFilesDir(null); + if (internalStorageFile != null) { + StatFs internalStorageStat = new StatFs(internalStorageFile.getPath()); + device.setStorageSize(getTotalInternalStorage(internalStorageStat)); + device.setFreeStorage(getUnusedInternalStorage(internalStorageStat)); + } + + final @Nullable StatFs externalStorageStat = getExternalStorageStat(internalStorageFile); + if (externalStorageStat != null) { + device.setExternalStorageSize(getTotalExternalStorage(externalStorageStat)); + device.setExternalFreeStorage(getUnusedExternalStorage(externalStorageStat)); + } + + if (device.getConnectionType() == null) { + // wifi, ethernet or cellular, null if none + device.setConnectionType( + ConnectivityChecker.getConnectionType(context, options.getLogger(), buildInfoProvider)); + } + } + + @SuppressWarnings("NewApi") + private TimeZone getTimeZone() { + if (buildInfoProvider.getSdkInfoVersion() >= Build.VERSION_CODES.N) { + LocaleList locales = context.getResources().getConfiguration().getLocales(); + if (!locales.isEmpty()) { + Locale locale = locales.get(0); + return Calendar.getInstance(locale).getTimeZone(); + } + } + return Calendar.getInstance().getTimeZone(); + } + + @SuppressWarnings("JdkObsolete") + private @Nullable Date getBootTime() { + try { + // if user changes the clock, will give a wrong answer, consider ACTION_TIME_CHANGED. + // currentTimeMillis returns UTC already + return DateUtils.getDateTime(System.currentTimeMillis() - SystemClock.elapsedRealtime()); + } catch (IllegalArgumentException e) { + options.getLogger().log(SentryLevel.ERROR, e, "Error getting the device's boot time."); + } + return null; + } + + private @Nullable Intent getBatteryIntent() { + return context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + } + + /** + * Get the device's current battery level (as a percentage of total). + * + * @return the device's current battery level (as a percentage of total), or null if unknown + */ + private @Nullable Float getBatteryLevel(final @NotNull Intent batteryIntent) { + try { + int level = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); + int scale = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, -1); + + if (level == -1 || scale == -1) { + return null; + } + + float percentMultiplier = 100.0f; + + return ((float) level / (float) scale) * percentMultiplier; + } catch (Throwable e) { + options.getLogger().log(SentryLevel.ERROR, "Error getting device battery level.", e); + return null; + } + } + + /** + * Checks whether or not the device is currently plugged in and charging, or null if unknown. + * + * @return whether or not the device is currently plugged in and charging, or null if unknown + */ + private @Nullable Boolean isCharging(final @NotNull Intent batteryIntent) { + try { + int plugged = batteryIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); + return plugged == BatteryManager.BATTERY_PLUGGED_AC + || plugged == BatteryManager.BATTERY_PLUGGED_USB; + } catch (Throwable e) { + options.getLogger().log(SentryLevel.ERROR, "Error getting device charging state.", e); + return null; + } + } + + private @Nullable Float getBatteryTemperature(final @NotNull Intent batteryIntent) { + try { + int temperature = batteryIntent.getIntExtra(EXTRA_TEMPERATURE, -1); + if (temperature != -1) { + return ((float) temperature) / 10; // celsius + } + } catch (Throwable e) { + options.getLogger().log(SentryLevel.ERROR, "Error getting battery temperature.", e); + } + return null; + } + + /** + * Get the device's current screen orientation. + * + * @return the device's current screen orientation, or null if unknown + */ + private @Nullable Device.DeviceOrientation getOrientation() { + Device.DeviceOrientation deviceOrientation = null; + try { + deviceOrientation = + DeviceOrientations.getOrientation(context.getResources().getConfiguration().orientation); + if (deviceOrientation == null) { + options + .getLogger() + .log( + SentryLevel.INFO, + "No device orientation available (ORIENTATION_SQUARE|ORIENTATION_UNDEFINED)"); + return null; + } + } catch (Throwable e) { + options.getLogger().log(SentryLevel.ERROR, "Error getting device orientation.", e); + } + return deviceOrientation; + } + + @SuppressWarnings({"ObsoleteSdkInt", "NewApi"}) + private @NotNull Long getMemorySize(final @NotNull ActivityManager.MemoryInfo memInfo) { + if (buildInfoProvider.getSdkInfoVersion() >= Build.VERSION_CODES.JELLY_BEAN) { + return memInfo.totalMem; + } + // using Runtime as a fallback + return java.lang.Runtime.getRuntime().totalMemory(); // JVM in bytes too + } + + /** + * Get the total amount of internal storage, in bytes. + * + * @return the total amount of internal storage, in bytes + */ + private @Nullable Long getTotalInternalStorage(final @NotNull StatFs stat) { + try { + long blockSize = getBlockSizeLong(stat); + long totalBlocks = getBlockCountLong(stat); + return totalBlocks * blockSize; + } catch (Throwable e) { + options.getLogger().log(SentryLevel.ERROR, "Error getting total internal storage amount.", e); + return null; + } + } + + @SuppressWarnings({"ObsoleteSdkInt", "NewApi"}) + private long getBlockSizeLong(final @NotNull StatFs stat) { + if (buildInfoProvider.getSdkInfoVersion() >= Build.VERSION_CODES.JELLY_BEAN_MR2) { + return stat.getBlockSizeLong(); + } + return getBlockSizeDep(stat); + } + + @SuppressWarnings({"deprecation"}) + private int getBlockSizeDep(final @NotNull StatFs stat) { + return stat.getBlockSize(); + } + + @SuppressWarnings({"ObsoleteSdkInt", "NewApi"}) + private long getBlockCountLong(final @NotNull StatFs stat) { + if (buildInfoProvider.getSdkInfoVersion() >= Build.VERSION_CODES.JELLY_BEAN_MR2) { + return stat.getBlockCountLong(); + } + return getBlockCountDep(stat); + } + + @SuppressWarnings({"deprecation"}) + private int getBlockCountDep(final @NotNull StatFs stat) { + return stat.getBlockCount(); + } + + @SuppressWarnings({"ObsoleteSdkInt", "NewApi"}) + private long getAvailableBlocksLong(final @NotNull StatFs stat) { + if (buildInfoProvider.getSdkInfoVersion() >= Build.VERSION_CODES.JELLY_BEAN_MR2) { + return stat.getAvailableBlocksLong(); + } + return getAvailableBlocksDep(stat); + } + + @SuppressWarnings({"deprecation"}) + private int getAvailableBlocksDep(final @NotNull StatFs stat) { + return stat.getAvailableBlocks(); + } + + /** + * Get the unused amount of internal storage, in bytes. + * + * @return the unused amount of internal storage, in bytes + */ + private @Nullable Long getUnusedInternalStorage(final @NotNull StatFs stat) { + try { + long blockSize = getBlockSizeLong(stat); + long availableBlocks = getAvailableBlocksLong(stat); + return availableBlocks * blockSize; + } catch (Throwable e) { + options + .getLogger() + .log(SentryLevel.ERROR, "Error getting unused internal storage amount.", e); + return null; + } + } + + private @Nullable StatFs getExternalStorageStat(final @Nullable File internalStorage) { + if (!isExternalStorageMounted()) { + File path = getExternalStorageDep(internalStorage); + if (path != null) { // && path.canRead()) { canRead() will read return false + return new StatFs(path.getPath()); + } + options.getLogger().log(SentryLevel.INFO, "Not possible to read external files directory"); + return null; + } + options.getLogger().log(SentryLevel.INFO, "External storage is not mounted or emulated."); + return null; + } + + @SuppressWarnings({"ObsoleteSdkInt", "NewApi"}) + private @Nullable File[] getExternalFilesDirs() { + if (buildInfoProvider.getSdkInfoVersion() >= Build.VERSION_CODES.KITKAT) { + return context.getExternalFilesDirs(null); + } else { + File single = context.getExternalFilesDir(null); + if (single != null) { + return new File[] {single}; + } + } + return null; + } + + private @Nullable File getExternalStorageDep(final @Nullable File internalStorage) { + final @Nullable File[] externalFilesDirs = getExternalFilesDirs(); + + if (externalFilesDirs != null) { + // return the 1st file which is not the emulated internal storage + String internalStoragePath = + internalStorage != null ? internalStorage.getAbsolutePath() : null; + for (File file : externalFilesDirs) { + // externalFilesDirs may contain null values :( + if (file == null) { + continue; + } + + // return the 1st file if you cannot compare with the internal one + if (internalStoragePath == null || internalStoragePath.isEmpty()) { + return file; + } + // if we are looking to the same directory, let's check the next one or no external storage + if (file.getAbsolutePath().contains(internalStoragePath)) { + continue; + } + return file; + } + } else { + options.getLogger().log(SentryLevel.INFO, "Not possible to read getExternalFilesDirs"); + } + return null; + } + + /** + * Get the total amount of external storage, in bytes, or null if no external storage is mounted. + * + * @return the total amount of external storage, in bytes, or null if no external storage is + * mounted + */ + private @Nullable Long getTotalExternalStorage(final @NotNull StatFs stat) { + try { + final long blockSize = getBlockSizeLong(stat); + final long totalBlocks = getBlockCountLong(stat); + return totalBlocks * blockSize; + } catch (Throwable e) { + options.getLogger().log(SentryLevel.ERROR, "Error getting total external storage amount.", e); + return null; + } + } + + private boolean isExternalStorageMounted() { + final String storageState = Environment.getExternalStorageState(); + return (Environment.MEDIA_MOUNTED.equals(storageState) + || Environment.MEDIA_MOUNTED_READ_ONLY.equals(storageState)) + && !Environment.isExternalStorageEmulated(); + } + + /** + * Get the unused amount of external storage, in bytes, or null if no external storage is mounted. + * + * @return the unused amount of external storage, in bytes, or null if no external storage is + * mounted + */ + private @Nullable Long getUnusedExternalStorage(final @NotNull StatFs stat) { + try { + final long blockSize = getBlockSizeLong(stat); + final long availableBlocks = getAvailableBlocksLong(stat); + return availableBlocks * blockSize; + } catch (Throwable e) { + options + .getLogger() + .log(SentryLevel.ERROR, "Error getting unused external storage amount.", e); + return null; + } + } + + private @Nullable String getDeviceId() { + try { + return Installation.id(context); + } catch (Throwable e) { + options.getLogger().log(SentryLevel.ERROR, "Error getting installationId.", e); + } + return null; + } +} diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/Installation.java b/sentry-android-core/src/main/java/io/sentry/android/core/Installation.java index 007bb306cdd..4ff7a661fa1 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/Installation.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/Installation.java @@ -12,7 +12,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; -final class Installation { +public final class Installation { @TestOnly static @Nullable String deviceId = null; @TestOnly static final String INSTALLATION = "INSTALLATION"; diff --git a/sentry/src/main/java/io/sentry/InternalSentrySdk.java b/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java similarity index 53% rename from sentry/src/main/java/io/sentry/InternalSentrySdk.java rename to sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java index 34b1540f9d9..389cfba2d60 100644 --- a/sentry/src/main/java/io/sentry/InternalSentrySdk.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java @@ -1,8 +1,16 @@ -package io.sentry; +package io.sentry.android.core; +import android.content.Context; +import io.sentry.HubAdapter; +import io.sentry.ILogger; +import io.sentry.ObjectWriter; +import io.sentry.Scope; +import io.sentry.SentryLevel; +import io.sentry.protocol.Device; import io.sentry.util.MapObjectWriter; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -10,17 +18,31 @@ @ApiStatus.Internal public final class InternalSentrySdk { + /** + * @return a copy of the current hub's topmost scope, or null in case the hub is disabled + */ + @Nullable + public static Scope getCurrentScope() { + final @NotNull AtomicReference scopeRef = new AtomicReference<>(); + HubAdapter.getInstance().withScope(scopeRef::set); + return scopeRef.get(); + } + @NotNull - public static Map serializeScope(@Nullable Scope scope) { + public static Map serializeScope( + @NotNull Context context, @NotNull SentryAndroidOptions options, @Nullable Scope scope) { final @NotNull Map data = new HashMap<>(); if (scope == null) { return data; } - final @NotNull SentryOptions options = scope.getOptions(); final @NotNull ILogger logger = options.getLogger(); final @NotNull ObjectWriter writer = new MapObjectWriter(data); + final @NotNull DeviceInfoUtil deviceInfoUtil = DeviceInfoUtil.getInstance(context, options); + final @NotNull Device deviceInfo = deviceInfoUtil.collectDeviceInformation(false, false); + scope.getContexts().setDevice(deviceInfo); + try { writer.name("user").value(logger, scope.getUser()); writer.name("contexts").value(logger, scope.getContexts()); diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/ContextUtilsUnitTests.kt b/sentry-android-core/src/test/java/io/sentry/android/core/ContextUtilsUnitTests.kt index 8f8846b9547..cdb3463297f 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/ContextUtilsUnitTests.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/ContextUtilsUnitTests.kt @@ -19,6 +19,7 @@ import org.robolectric.shadows.ShadowBuild import kotlin.test.BeforeTest import kotlin.test.Test import kotlin.test.assertEquals +import kotlin.test.assertFalse import kotlin.test.assertNotNull import kotlin.test.assertNull import kotlin.test.assertTrue @@ -83,8 +84,8 @@ class ContextUtilsUnitTests { @Test fun `isSideLoaded returns true for test context`() { val sideLoadedInfo = - ContextUtils.getSideLoadedInfo(context, logger, BuildInfoProvider(logger)) - assertEquals("true", sideLoadedInfo?.get("isSideLoaded")) + ContextUtils.retrieveSideLoadedInfo(context, logger, BuildInfoProvider(logger)) + assertTrue(sideLoadedInfo!!.isSideLoaded) } @Test @@ -96,9 +97,9 @@ class ContextUtilsUnitTests { whenever(mock.packageManager).thenReturn(mockedPackageManager) } val sideLoadedInfo = - ContextUtils.getSideLoadedInfo(mockedContext, logger, BuildInfoProvider(logger)) - assertEquals("false", sideLoadedInfo?.get("isSideLoaded")) - assertEquals("play.google.com", sideLoadedInfo?.get("installerStore")) + ContextUtils.retrieveSideLoadedInfo(mockedContext, logger, BuildInfoProvider(logger)) + assertFalse(sideLoadedInfo!!.isSideLoaded) + assertEquals("play.google.com", sideLoadedInfo.installerStore) } @Test diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/DefaultAndroidEventProcessorTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/DefaultAndroidEventProcessorTest.kt index 8747409ccea..514826ff967 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/DefaultAndroidEventProcessorTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/DefaultAndroidEventProcessorTest.kt @@ -13,10 +13,6 @@ import io.sentry.SentryLevel import io.sentry.SentryTracer import io.sentry.TransactionContext import io.sentry.TypeCheckHint.SENTRY_DART_SDK_NAME -import io.sentry.android.core.DefaultAndroidEventProcessor.EMULATOR -import io.sentry.android.core.DefaultAndroidEventProcessor.KERNEL_VERSION -import io.sentry.android.core.DefaultAndroidEventProcessor.ROOTED -import io.sentry.android.core.DefaultAndroidEventProcessor.SIDE_LOADED import io.sentry.android.core.internal.util.CpuInfoUtils import io.sentry.protocol.OperatingSystem import io.sentry.protocol.SdkVersion @@ -80,6 +76,7 @@ class DefaultAndroidEventProcessorTest { fun `set up`() { context = ApplicationProvider.getApplicationContext() AppState.getInstance().resetInstance() + DeviceInfoUtil.resetInstance() } @Test @@ -295,19 +292,6 @@ class DefaultAndroidEventProcessorTest { } } - @Test - fun `Executor service should be called on ctor`() { - val sut = fixture.getSut(context) - - val contextData = sut.contextData.get() - - assertNotNull(contextData) - assertNotNull(contextData[ROOTED]) - assertNotNull(contextData[KERNEL_VERSION]) - assertNotNull(contextData[EMULATOR]) - assertNotNull(contextData[SIDE_LOADED]) - } - @Test fun `Processor won't throw exception`() { val sut = fixture.getSut(context) @@ -323,7 +307,7 @@ class DefaultAndroidEventProcessorTest { @Test fun `Processor won't throw exception when theres a hint`() { val processor = - DefaultAndroidEventProcessor(context, fixture.buildInfo, mock(), fixture.options) + DefaultAndroidEventProcessor(context, fixture.buildInfo, fixture.options) val hints = HintUtils.createWithTypeCheckHint(CachedEvent()) processor.process(SentryEvent(), hints) @@ -576,13 +560,4 @@ class DefaultAndroidEventProcessorTest { assertNull(thread.isMain) } } - - @Test - fun `does not perform root check if root checker is disabled`() { - fixture.options.isEnableRootCheck = false - val sut = fixture.getSut(context) - - val contextData = sut.contextData.get() - assertNull(contextData[ROOTED]) - } } diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/DeviceInfoUtilTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/DeviceInfoUtilTest.kt new file mode 100644 index 00000000000..5c90395e3b8 --- /dev/null +++ b/sentry-android-core/src/test/java/io/sentry/android/core/DeviceInfoUtilTest.kt @@ -0,0 +1,156 @@ +package io.sentry.android.core + +import android.content.Context +import android.content.Intent +import android.os.BatteryManager +import android.provider.Settings +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import io.sentry.android.core.internal.util.CpuInfoUtils +import org.junit.runner.RunWith +import kotlin.test.BeforeTest +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull + +@RunWith(AndroidJUnit4::class) +class DeviceInfoUtilTest { + + private lateinit var context: Context + + @Suppress("deprecation") + @BeforeTest + fun `set up`() { + context = ApplicationProvider.getApplicationContext() + context.sendStickyBroadcast( + Intent(Intent.ACTION_BATTERY_CHANGED).putExtra( + BatteryManager.EXTRA_LEVEL, + 75 + ).putExtra(BatteryManager.EXTRA_PLUGGED, 0) + ) + Settings.Global.putString(context.contentResolver, "device_name", "sentry") + DeviceInfoUtil.resetInstance() + } + + @Test + fun `provides os and sideloaded info`() { + val deviceInfoUtil = DeviceInfoUtil.getInstance(context, SentryAndroidOptions()) + + val os = deviceInfoUtil.operatingSystem + val sideLoadedInfo = deviceInfoUtil.sideLoadedInfo + val deviceInfo = deviceInfoUtil.collectDeviceInformation(false, false) + + assertNotNull(os.kernelVersion) + assertNotNull(os.isRooted) + + assertNotNull(sideLoadedInfo) + assertNotNull(sideLoadedInfo.isSideLoaded) + + assertNotNull(deviceInfo.isSimulator) + } + + @Test + fun `does not include device name when PII is disabled`() { + val deviceInfoUtil = DeviceInfoUtil.getInstance( + context, + SentryAndroidOptions().apply { + isSendDefaultPii = false + } + ) + val deviceInfo = deviceInfoUtil.collectDeviceInformation(false, false) + assertNull(deviceInfo.name) + } + + @Test + fun `does include device name when pii is enabled`() { + val deviceInfoUtil = DeviceInfoUtil.getInstance( + context, + SentryAndroidOptions().apply { + isSendDefaultPii = true + } + ) + val deviceInfo = deviceInfoUtil.collectDeviceInformation(false, false) + assertNotNull(deviceInfo.name) + } + + @Test + fun `does include cpu data`() { + CpuInfoUtils.getInstance().setCpuMaxFrequencies(listOf(1024)) + val deviceInfoUtil = DeviceInfoUtil.getInstance(context, SentryAndroidOptions()) + val deviceInfo = deviceInfoUtil.collectDeviceInformation(false, false) + + assertEquals(1, deviceInfo.processorCount) + assertEquals(1024.0, deviceInfo.processorFrequency) + } + + @Test + fun `does include device io data when enabled`() { + val options = SentryAndroidOptions().apply { + isCollectAdditionalContext = true + } + val deviceInfoUtil = DeviceInfoUtil.getInstance(context, options) + val deviceInfo = deviceInfoUtil.collectDeviceInformation(true, false) + + // all values are 0 when running via robolectric + assertNotNull(deviceInfo.memorySize) + assertNotNull(deviceInfo.storageSize) + assertNotNull(deviceInfo.freeStorage) + } + + @Test + fun `does not include device io data when disabled`() { + val options = SentryAndroidOptions().apply { + isCollectAdditionalContext = true + } + val deviceInfoUtil = DeviceInfoUtil.getInstance(context, options) + val deviceInfo = deviceInfoUtil.collectDeviceInformation(false, false) + + assertNull(deviceInfo.memorySize) + assertNull(deviceInfo.storageSize) + assertNull(deviceInfo.freeStorage) + } + + @Test + fun `does include dynamic data when enabled`() { + val options = SentryAndroidOptions().apply { + isCollectAdditionalContext = true + } + val deviceInfoUtil = DeviceInfoUtil.getInstance(context, options) + val deviceInfo = deviceInfoUtil.collectDeviceInformation(true, true) + + // all values are 0 when running via robolectric + assertNotNull(deviceInfo.freeMemory) + assertNotNull(deviceInfo.isLowMemory) + } + + @Test + fun `does not include dynamic data when disabled`() { + val options = SentryAndroidOptions().apply { + isCollectAdditionalContext = true + } + val deviceInfoUtil = DeviceInfoUtil.getInstance(context, options) + val deviceInfo = deviceInfoUtil.collectDeviceInformation(true, false) + + assertNull(deviceInfo.freeMemory) + assertNull(deviceInfo.isLowMemory) + } + + @Test + fun `does perform root check if root checker is enabled`() { + val options = SentryAndroidOptions().apply { + isEnableRootCheck = true + } + val deviceInfoUtil = DeviceInfoUtil.getInstance(context, options) + assertNotNull(deviceInfoUtil.operatingSystem.isRooted) + } + + @Test + fun `does not perform root check if root checker is disabled`() { + val options = SentryAndroidOptions().apply { + isEnableRootCheck = false + } + val deviceInfoUtil = DeviceInfoUtil.getInstance(context, options) + assertNull(deviceInfoUtil.operatingSystem.isRooted) + } +} diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/InternalSentrySdkTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/InternalSentrySdkTest.kt new file mode 100644 index 00000000000..f8e112d46d4 --- /dev/null +++ b/sentry-android-core/src/test/java/io/sentry/android/core/InternalSentrySdkTest.kt @@ -0,0 +1,106 @@ +package io.sentry.android.core + +import android.content.Context +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import io.sentry.Breadcrumb +import io.sentry.Hub +import io.sentry.NoOpHub +import io.sentry.Scope +import io.sentry.Sentry +import io.sentry.SentryOptions +import io.sentry.protocol.App +import io.sentry.protocol.Contexts +import io.sentry.protocol.User +import org.junit.runner.RunWith +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever +import kotlin.test.BeforeTest +import kotlin.test.Test +import kotlin.test.assertNotNull +import kotlin.test.assertNull +import kotlin.test.assertTrue + +@RunWith(AndroidJUnit4::class) +class InternalSentrySdkTest { + + private lateinit var context: Context + + @BeforeTest + fun `set up`() { + context = ApplicationProvider.getApplicationContext() + DeviceInfoUtil.resetInstance() + } + + @Test + fun `current scope returns null when hub is no-op`() { + Sentry.setCurrentHub(NoOpHub.getInstance()) + val scope = InternalSentrySdk.getCurrentScope() + assertNull(scope) + } + + @Test + fun `current scope returns obj when hub is active`() { + Sentry.setCurrentHub( + Hub( + SentryOptions().apply { + dsn = "https://key@uri/1234567" + } + ) + ) + val scope = InternalSentrySdk.getCurrentScope() + assertNotNull(scope) + } + + @Test + fun `serializeScope correctly creates top level map`() { + val options = SentryAndroidOptions() + val scope = Scope(options) + + scope.user = User().apply { + name = "John" + } + scope.addBreadcrumb(Breadcrumb.ui("ui.click", "button_login")) + scope.contexts.setApp( + App().apply { + appName = "Example App" + } + ) + scope.setTag("variant", "yellow") + + val serializedScope = InternalSentrySdk.serializeScope( + context, + options, + scope + ) + + assertTrue(serializedScope.containsKey("user")) + assertTrue(serializedScope.containsKey("contexts")) + assertTrue((serializedScope["contexts"] as Map<*, *>).containsKey("device")) + + assertTrue(serializedScope.containsKey("tags")) + assertTrue(serializedScope.containsKey("extras")) + assertTrue(serializedScope.containsKey("fingerprint")) + assertTrue(serializedScope.containsKey("level")) + assertTrue(serializedScope.containsKey("breadcrumbs")) + } + + @Test + fun `serializeScope returns empty map in case scope is null`() { + val options = SentryAndroidOptions() + val serializedScope = InternalSentrySdk.serializeScope(context, options, null) + assertTrue(serializedScope.isEmpty()) + } + + @Test + fun `serializeScope returns empty map in case scope serialization fails`() { + val options = SentryAndroidOptions() + val scope = mock() + + whenever(scope.contexts).thenReturn(Contexts()) + whenever(scope.user).thenThrow(IllegalStateException("something is off")) + + val serializedScope = InternalSentrySdk.serializeScope(context, options, scope) + assertTrue(serializedScope.isEmpty()) + } +} diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index de8321a3f7f..7bba21c42aa 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -655,11 +655,6 @@ public abstract interface class io/sentry/IntegrationName { public fun getIntegrationName ()Ljava/lang/String; } -public final class io/sentry/InternalSentrySdk { - public fun ()V - public static fun serializeScope (Lio/sentry/Scope;)Ljava/util/Map; -} - public final class io/sentry/IpAddressUtils { public static final field DEFAULT_IP_ADDRESS Ljava/lang/String; public static fun isDefault (Ljava/lang/String;)Z @@ -1179,7 +1174,10 @@ public final class io/sentry/Scope { public fun clearAttachments ()V public fun clearBreadcrumbs ()V public fun clearTransaction ()V + public fun getBreadcrumbs ()Ljava/util/Queue; public fun getContexts ()Lio/sentry/protocol/Contexts; + public fun getExtras ()Ljava/util/Map; + public fun getFingerprint ()Ljava/util/List; public fun getLevel ()Lio/sentry/SentryLevel; public fun getRequest ()Lio/sentry/protocol/Request; public fun getSession ()Lio/sentry/Session; diff --git a/sentry/src/main/java/io/sentry/Scope.java b/sentry/src/main/java/io/sentry/Scope.java index 265b9b8a301..025419c2405 100644 --- a/sentry/src/main/java/io/sentry/Scope.java +++ b/sentry/src/main/java/io/sentry/Scope.java @@ -277,8 +277,9 @@ public void setRequest(final @Nullable Request request) { * * @return the fingerprint list */ + @ApiStatus.Internal @NotNull - List getFingerprint() { + public List getFingerprint() { return fingerprint; } @@ -303,8 +304,9 @@ public void setFingerprint(final @NotNull List fingerprint) { * * @return the breadcrumbs queue */ + @ApiStatus.Internal @NotNull - Queue getBreadcrumbs() { + public Queue getBreadcrumbs() { return breadcrumbs; } @@ -469,8 +471,9 @@ public void removeTag(final @NotNull String key) { * * @return the extra map */ + @ApiStatus.Internal @NotNull - Map getExtras() { + public Map getExtras() { return extra; } diff --git a/sentry/src/test/java/io/sentry/InternalSentrySdkTest.kt b/sentry/src/test/java/io/sentry/InternalSentrySdkTest.kt deleted file mode 100644 index 9100719d011..00000000000 --- a/sentry/src/test/java/io/sentry/InternalSentrySdkTest.kt +++ /dev/null @@ -1,54 +0,0 @@ -package io.sentry - -import io.sentry.protocol.App -import io.sentry.protocol.User -import org.mockito.kotlin.mock -import org.mockito.kotlin.whenever -import kotlin.test.Test -import kotlin.test.assertTrue - -class InternalSentrySdkTest { - @Test - fun `serializeScope correctly creates top level map`() { - val options = SentryOptions() - val scope = Scope(options) - - scope.user = User().apply { - name = "John" - } - scope.addBreadcrumb(Breadcrumb.ui("ui.click", "button_login")) - scope.contexts.setApp( - App().apply { - appName = "Example App" - } - ) - scope.setTag("variant", "yellow") - - val serializedScope = InternalSentrySdk.serializeScope(scope) - - assertTrue(serializedScope.containsKey("user")) - assertTrue(serializedScope.containsKey("contexts")) - assertTrue(serializedScope.containsKey("tags")) - assertTrue(serializedScope.containsKey("extras")) - assertTrue(serializedScope.containsKey("fingerprint")) - assertTrue(serializedScope.containsKey("level")) - assertTrue(serializedScope.containsKey("breadcrumbs")) - } - - @Test - fun `serializeScope returns empty map in case scope is null`() { - val serializedScope = InternalSentrySdk.serializeScope(null) - assertTrue(serializedScope.isEmpty()) - } - - @Test - fun `serializeScope returns empty map in case scope serialization fails`() { - val scope = mock() - val options = SentryOptions() - whenever(scope.options).thenReturn(options) - whenever(scope.user).thenThrow(IllegalStateException("something is off")) - - val serializedScope = InternalSentrySdk.serializeScope(scope) - assertTrue(serializedScope.isEmpty()) - } -} diff --git a/sentry/src/test/java/io/sentry/util/MapObjectWriterTest.kt b/sentry/src/test/java/io/sentry/util/MapObjectWriterTest.kt index 6a3308f9fdd..4127a8c840f 100644 --- a/sentry/src/test/java/io/sentry/util/MapObjectWriterTest.kt +++ b/sentry/src/test/java/io/sentry/util/MapObjectWriterTest.kt @@ -63,7 +63,10 @@ class MapObjectWriterTest { writer.name("InetAddress").value(logger, Inet4Address.getByName("1.1.1.1")) writer.name("UUID").value(logger, UUID.fromString("00000000-1111-2222-3333-444444444444")) writer.name("Currency").value(logger, Currency.getInstance("EUR")) - writer.name("Calendar").value(logger, Calendar.getInstance(TimeZone.getTimeZone("UTC")).apply { timeInMillis = 0 }) + writer.name("Calendar").value( + logger, + Calendar.getInstance(TimeZone.getTimeZone("UTC")).apply { timeInMillis = 0 } + ) writer.name("Enum").value(logger, BasicEnum.A) assertEquals(null, data["null"]) From 26ab9666dc6e8cba17298f8e399e3481c32c9f65 Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Wed, 12 Jul 2023 09:03:57 +0200 Subject: [PATCH 05/10] Fix back-fill user if not manually set on scope --- .../java/io/sentry/android/core/InternalSentrySdk.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java b/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java index 389cfba2d60..90b82daf54f 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java @@ -7,6 +7,7 @@ import io.sentry.Scope; import io.sentry.SentryLevel; import io.sentry.protocol.Device; +import io.sentry.protocol.User; import io.sentry.util.MapObjectWriter; import java.util.HashMap; import java.util.Map; @@ -42,6 +43,15 @@ public static Map serializeScope( final @NotNull DeviceInfoUtil deviceInfoUtil = DeviceInfoUtil.getInstance(context, options); final @NotNull Device deviceInfo = deviceInfoUtil.collectDeviceInformation(false, false); scope.getContexts().setDevice(deviceInfo); + @Nullable User user = scope.getUser(); + if (user == null) { + user = new User(); + user.setId(Installation.id(context)); + } + if (user.getId() == null) { + user.setId(Installation.id(context)); + } + scope.setUser(user); try { writer.name("user").value(logger, scope.getUser()); From 74cbd447eaa6836f437a130e4d93afabb68622ab Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Wed, 12 Jul 2023 09:04:06 +0200 Subject: [PATCH 06/10] Add missing os context --- .../src/main/java/io/sentry/android/core/InternalSentrySdk.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java b/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java index 90b82daf54f..bb0277d68de 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java @@ -43,6 +43,8 @@ public static Map serializeScope( final @NotNull DeviceInfoUtil deviceInfoUtil = DeviceInfoUtil.getInstance(context, options); final @NotNull Device deviceInfo = deviceInfoUtil.collectDeviceInformation(false, false); scope.getContexts().setDevice(deviceInfo); + scope.getContexts().setOperatingSystem(deviceInfoUtil.getOperatingSystem()); + @Nullable User user = scope.getUser(); if (user == null) { user = new User(); From e856a09651ab94efd47d76e3e91189a488ef06a8 Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Wed, 12 Jul 2023 10:38:41 +0200 Subject: [PATCH 07/10] Enrich os, user and app context --- .../io/sentry/android/core/ContextUtils.java | 35 +++++++++++++ .../core/DefaultAndroidEventProcessor.java | 36 +------------ .../android/core/InternalSentrySdk.java | 51 ++++++++++++++----- .../android/core/InternalSentrySdkTest.kt | 31 +++++++++++ 4 files changed, 104 insertions(+), 49 deletions(-) diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ContextUtils.java b/sentry-android-core/src/main/java/io/sentry/android/core/ContextUtils.java index 94743382ec9..2c60b5abf8f 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/ContextUtils.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ContextUtils.java @@ -2,6 +2,7 @@ import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; import static android.content.Context.ACTIVITY_SERVICE; +import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED; import android.annotation.SuppressLint; import android.app.ActivityManager; @@ -15,6 +16,7 @@ import android.util.DisplayMetrics; import io.sentry.ILogger; import io.sentry.SentryLevel; +import io.sentry.protocol.App; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; @@ -343,4 +345,37 @@ static boolean isForegroundImportance(final @NotNull Context context) { return null; } } + + // we perform an if-check for that, but lint fails to recognize + @SuppressLint("NewApi") + static void setAppPackageInfo( + final @NotNull PackageInfo packageInfo, + final @NotNull BuildInfoProvider buildInfoProvider, + final @NotNull App app) { + app.setAppIdentifier(packageInfo.packageName); + app.setAppVersion(packageInfo.versionName); + app.setAppBuild(ContextUtils.getVersionCode(packageInfo, buildInfoProvider)); + + if (buildInfoProvider.getSdkInfoVersion() >= Build.VERSION_CODES.JELLY_BEAN) { + final Map permissions = new HashMap<>(); + final String[] requestedPermissions = packageInfo.requestedPermissions; + final int[] requestedPermissionsFlags = packageInfo.requestedPermissionsFlags; + + if (requestedPermissions != null + && requestedPermissions.length > 0 + && requestedPermissionsFlags != null + && requestedPermissionsFlags.length > 0) { + for (int i = 0; i < requestedPermissions.length; i++) { + String permission = requestedPermissions[i]; + permission = permission.substring(permission.lastIndexOf('.') + 1); + + final boolean granted = + (requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED) + == REQUESTED_PERMISSION_GRANTED; + permissions.put(permission, granted ? "granted" : "not_granted"); + } + } + app.setPermissions(permissions); + } + } } diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java index e2e635e1d13..75cc4821367 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java @@ -1,12 +1,8 @@ package io.sentry.android.core; -import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED; - -import android.annotation.SuppressLint; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; -import android.os.Build; import io.sentry.DateUtils; import io.sentry.EventProcessor; import io.sentry.Hint; @@ -21,7 +17,6 @@ import io.sentry.protocol.User; import io.sentry.util.HintUtils; import io.sentry.util.Objects; -import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.concurrent.ExecutorService; @@ -185,7 +180,7 @@ private void setPackageInfo(final @NotNull SentryBaseEvent event, final @NotNull String versionCode = ContextUtils.getVersionCode(packageInfo, buildInfoProvider); setDist(event, versionCode); - setAppPackageInfo(app, packageInfo); + ContextUtils.setAppPackageInfo(packageInfo, buildInfoProvider, app); } } @@ -210,35 +205,6 @@ private void setAppExtras(final @NotNull App app, final @NotNull Hint hint) { } } - @SuppressLint("NewApi") // we perform an if-check for that, but lint fails to recognize - private void setAppPackageInfo(final @NotNull App app, final @NotNull PackageInfo packageInfo) { - app.setAppIdentifier(packageInfo.packageName); - app.setAppVersion(packageInfo.versionName); - app.setAppBuild(ContextUtils.getVersionCode(packageInfo, buildInfoProvider)); - - if (buildInfoProvider.getSdkInfoVersion() >= Build.VERSION_CODES.JELLY_BEAN) { - final Map permissions = new HashMap<>(); - final String[] requestedPermissions = packageInfo.requestedPermissions; - final int[] requestedPermissionsFlags = packageInfo.requestedPermissionsFlags; - - if (requestedPermissions != null - && requestedPermissions.length > 0 - && requestedPermissionsFlags != null - && requestedPermissionsFlags.length > 0) { - for (int i = 0; i < requestedPermissions.length; i++) { - String permission = requestedPermissions[i]; - permission = permission.substring(permission.lastIndexOf('.') + 1); - - final boolean granted = - (requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED) - == REQUESTED_PERMISSION_GRANTED; - permissions.put(permission, granted ? "granted" : "not_granted"); - } - } - app.setPermissions(permissions); - } - } - /** * Sets the default user which contains only the userId. * diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java b/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java index bb0277d68de..6bf8b44a047 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java @@ -1,11 +1,15 @@ package io.sentry.android.core; import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import io.sentry.DateUtils; import io.sentry.HubAdapter; import io.sentry.ILogger; import io.sentry.ObjectWriter; import io.sentry.Scope; import io.sentry.SentryLevel; +import io.sentry.protocol.App; import io.sentry.protocol.Device; import io.sentry.protocol.User; import io.sentry.util.MapObjectWriter; @@ -40,22 +44,41 @@ public static Map serializeScope( final @NotNull ILogger logger = options.getLogger(); final @NotNull ObjectWriter writer = new MapObjectWriter(data); - final @NotNull DeviceInfoUtil deviceInfoUtil = DeviceInfoUtil.getInstance(context, options); - final @NotNull Device deviceInfo = deviceInfoUtil.collectDeviceInformation(false, false); - scope.getContexts().setDevice(deviceInfo); - scope.getContexts().setOperatingSystem(deviceInfoUtil.getOperatingSystem()); + try { - @Nullable User user = scope.getUser(); - if (user == null) { - user = new User(); - user.setId(Installation.id(context)); - } - if (user.getId() == null) { - user.setId(Installation.id(context)); - } - scope.setUser(user); + final @NotNull DeviceInfoUtil deviceInfoUtil = DeviceInfoUtil.getInstance(context, options); + final @NotNull Device deviceInfo = deviceInfoUtil.collectDeviceInformation(false, false); + scope.getContexts().setDevice(deviceInfo); + scope.getContexts().setOperatingSystem(deviceInfoUtil.getOperatingSystem()); + + // user + @Nullable User user = scope.getUser(); + if (user == null) { + user = new User(); + scope.setUser(user); + } + if (user.getId() == null) { + user.setId(Installation.id(context)); + } + + // app context + @Nullable App app = scope.getContexts().getApp(); + if (app == null) { + app = new App(); + app.setAppName(ContextUtils.getApplicationName(context, options.getLogger())); + app.setAppStartTime(DateUtils.toUtilDate(AppStartState.getInstance().getAppStartTime())); + + final @NotNull BuildInfoProvider buildInfoProvider = + new BuildInfoProvider(options.getLogger()); + final @Nullable PackageInfo packageInfo = + ContextUtils.getPackageInfo( + context, PackageManager.GET_PERMISSIONS, options.getLogger(), buildInfoProvider); + if (packageInfo != null) { + ContextUtils.setAppPackageInfo(packageInfo, buildInfoProvider, app); + } + scope.getContexts().setApp(app); + } - try { writer.name("user").value(logger, scope.getUser()); writer.name("contexts").value(logger, scope.getContexts()); writer.name("tags").value(logger, scope.getTags()); diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/InternalSentrySdkTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/InternalSentrySdkTest.kt index f8e112d46d4..7f642b36ca3 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/InternalSentrySdkTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/InternalSentrySdkTest.kt @@ -17,6 +17,7 @@ import org.mockito.kotlin.mock import org.mockito.kotlin.whenever import kotlin.test.BeforeTest import kotlin.test.Test +import kotlin.test.assertEquals import kotlin.test.assertNotNull import kotlin.test.assertNull import kotlin.test.assertTrue @@ -103,4 +104,34 @@ class InternalSentrySdkTest { val serializedScope = InternalSentrySdk.serializeScope(context, options, scope) assertTrue(serializedScope.isEmpty()) } + + @Test + fun `serializeScope provides fallback user if none is set`() { + val options = SentryAndroidOptions() + val scope = Scope(options) + scope.user = null + + val serializedScope = InternalSentrySdk.serializeScope(context, options, scope) + assertTrue((serializedScope["user"] as Map<*, *>).containsKey("id")) + } + + @Test + fun `serializeScope does not override user-id`() { + val options = SentryAndroidOptions() + val scope = Scope(options) + scope.user = User().apply { id = "abc" } + + val serializedScope = InternalSentrySdk.serializeScope(context, options, scope) + assertEquals("abc", (serializedScope["user"] as Map<*, *>)["id"]) + } + + @Test + fun `serializeScope provides fallback app data if none is set`() { + val options = SentryAndroidOptions() + val scope = Scope(options) + scope.setContexts("app", null) + + val serializedScope = InternalSentrySdk.serializeScope(context, options, scope) + assertTrue(((serializedScope["contexts"] as Map<*, *>)["app"] as Map<*, *>).containsKey("app_name")) + } } From 09953d7ddfa9340ceaa71c791a2001771cca7806 Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Thu, 13 Jul 2023 09:11:45 +0200 Subject: [PATCH 08/10] Add InternalSentrySdk.captureEnvelope --- .../api/sentry-android-core.api | 1 + .../android/core/InternalSentrySdk.java | 92 +++++++++++- .../android/core/InternalSentrySdkTest.kt | 137 +++++++++++++++++- 3 files changed, 227 insertions(+), 3 deletions(-) diff --git a/sentry-android-core/api/sentry-android-core.api b/sentry-android-core/api/sentry-android-core.api index f1be1674040..95e811834f7 100644 --- a/sentry-android-core/api/sentry-android-core.api +++ b/sentry-android-core/api/sentry-android-core.api @@ -179,6 +179,7 @@ public final class io/sentry/android/core/Installation { public final class io/sentry/android/core/InternalSentrySdk { public fun ()V + public static fun captureEnvelope ([B)Lio/sentry/protocol/SentryId; public static fun getCurrentScope ()Lio/sentry/Scope; public static fun serializeScope (Landroid/content/Context;Lio/sentry/android/core/SentryAndroidOptions;Lio/sentry/Scope;)Ljava/util/Map; } diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java b/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java index 6bf8b44a047..02a79105237 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java @@ -5,21 +5,33 @@ import android.content.pm.PackageManager; import io.sentry.DateUtils; import io.sentry.HubAdapter; +import io.sentry.IHub; import io.sentry.ILogger; +import io.sentry.ISerializer; import io.sentry.ObjectWriter; import io.sentry.Scope; +import io.sentry.SentryEnvelope; +import io.sentry.SentryEnvelopeItem; +import io.sentry.SentryEvent; import io.sentry.SentryLevel; +import io.sentry.SentryOptions; +import io.sentry.Session; import io.sentry.protocol.App; import io.sentry.protocol.Device; +import io.sentry.protocol.SentryId; import io.sentry.protocol.User; import io.sentry.util.MapObjectWriter; +import java.io.ByteArrayInputStream; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +/** Sentry SDK internal API methods meant for being used by the Sentry Hybrid SDKs. */ @ApiStatus.Internal public final class InternalSentrySdk { @@ -47,7 +59,7 @@ public static Map serializeScope( try { final @NotNull DeviceInfoUtil deviceInfoUtil = DeviceInfoUtil.getInstance(context, options); - final @NotNull Device deviceInfo = deviceInfoUtil.collectDeviceInformation(false, false); + final @NotNull Device deviceInfo = deviceInfoUtil.collectDeviceInformation(true, true); scope.getContexts().setDevice(deviceInfo); scope.getContexts().setOperatingSystem(deviceInfoUtil.getOperatingSystem()); @@ -93,4 +105,82 @@ public static Map serializeScope( return data; } + + /** + * Captures the provided envelope. Compared to {@link IHub#captureEvent(SentryEvent)} this method + * - will not enrich events with additional data (e.g. scope) - will not execute beforeSend: it's + * up to the caller to take care of this - will not perform any sampling: it's up to the caller to + * take care of this - will enrich the envelope with a Session updates is applicable + * + * @param envelopeData the serialized envelope data + * @return The Id (SentryId object) of the event + * @throws Exception In case the provided envelope could not be parsed / is invalid + */ + public static SentryId captureEnvelope(final @NotNull byte[] envelopeData) throws Exception { + final @NotNull IHub hub = HubAdapter.getInstance(); + final @NotNull SentryOptions options = hub.getOptions(); + + final @NotNull ISerializer serializer = options.getSerializer(); + final @Nullable SentryEnvelope envelope = + options.getEnvelopeReader().read(new ByteArrayInputStream(envelopeData)); + if (envelope == null) { + throw new IllegalArgumentException("Envelope could not be read"); + } + + final @NotNull List envelopeItems = new ArrayList<>(); + + // determine session state based on events inside envelope + @Nullable Session.State status = null; + boolean crashedOrErrored = false; + for (SentryEnvelopeItem item : envelope.getItems()) { + envelopeItems.add(item); + + final SentryEvent event = item.getEvent(serializer); + if (event != null) { + if (event.isCrashed()) { + status = Session.State.Crashed; + } + if (event.isCrashed() || event.isErrored()) { + crashedOrErrored = true; + } + } + } + + // update session and add it to envelope if necessary + final @Nullable Session session = updateSession(hub, options, status, crashedOrErrored); + if (session != null) { + final SentryEnvelopeItem sessionItem = SentryEnvelopeItem.fromSession(serializer, session); + envelopeItems.add(sessionItem); + } + + final SentryEnvelope repackagedEnvelope = + new SentryEnvelope(envelope.getHeader(), envelopeItems); + return hub.captureEnvelope(repackagedEnvelope); + } + + @Nullable + private static Session updateSession( + @NotNull IHub hub, + @NotNull SentryOptions options, + final @Nullable Session.State status, + final boolean crashedOrErrored) { + final @NotNull AtomicReference sessionRef = new AtomicReference<>(); + hub.withScope( + scope -> { + final @Nullable Session session = scope.getSession(); + if (session != null) { + final boolean updated = session.update(status, null, crashedOrErrored, null); + // if we have an uncaughtExceptionHint we can end the session. + if (updated) { + if (session.getStatus() == Session.State.Crashed) { + session.end(); + } + sessionRef.set(session); + } + } else { + options.getLogger().log(SentryLevel.INFO, "Session is null on updateSession"); + } + }); + return sessionRef.get(); + } } diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/InternalSentrySdkTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/InternalSentrySdkTest.kt index 7f642b36ca3..2e0537365d7 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/InternalSentrySdkTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/InternalSentrySdkTest.kt @@ -4,20 +4,35 @@ import android.content.Context import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import io.sentry.Breadcrumb +import io.sentry.Hint import io.sentry.Hub -import io.sentry.NoOpHub import io.sentry.Scope import io.sentry.Sentry +import io.sentry.SentryEnvelope +import io.sentry.SentryEnvelopeHeader +import io.sentry.SentryEnvelopeItem +import io.sentry.SentryEvent +import io.sentry.SentryExceptionFactory +import io.sentry.SentryItemType import io.sentry.SentryOptions +import io.sentry.Session +import io.sentry.exception.ExceptionMechanismException import io.sentry.protocol.App import io.sentry.protocol.Contexts +import io.sentry.protocol.Mechanism +import io.sentry.protocol.SentryId import io.sentry.protocol.User +import io.sentry.transport.ITransport import org.junit.runner.RunWith import org.mockito.kotlin.mock import org.mockito.kotlin.whenever +import java.io.ByteArrayInputStream +import java.io.ByteArrayOutputStream +import java.io.InputStreamReader import kotlin.test.BeforeTest import kotlin.test.Test import kotlin.test.assertEquals +import kotlin.test.assertFails import kotlin.test.assertNotNull import kotlin.test.assertNull import kotlin.test.assertTrue @@ -27,6 +42,57 @@ class InternalSentrySdkTest { private lateinit var context: Context + class Fixture { + val capturedEnvelopes = mutableListOf() + lateinit var options: SentryOptions + + fun init(context: Context) { + SentryAndroid.init(context) { options -> + this@Fixture.options = options + options.dsn = "https://key@host/proj" + options.setTransportFactory { _, _ -> + object : ITransport { + override fun close() { + // no-op + } + + override fun send(envelope: SentryEnvelope, hint: Hint) { + capturedEnvelopes.add(envelope) + } + + override fun flush(timeoutMillis: Long) { + // no-op + } + } + } + } + + capturedEnvelopes.clear() + } + + fun captureEnvelopeWithEvent(event: SentryEvent = SentryEvent()) { + // create an envelope with session data + val options = Sentry.getCurrentHub().options + val eventId = SentryId() + val header = SentryEnvelopeHeader(eventId) + val eventItem = SentryEnvelopeItem.fromEvent(options.serializer, event) + + val envelope = SentryEnvelope( + header, + listOf( + eventItem + ) + ) + + // serialize to byte array + val outputStream = ByteArrayOutputStream() + options.serializer.serialize(envelope, outputStream) + val data = outputStream.toByteArray() + + InternalSentrySdk.captureEnvelope(data) + } + } + @BeforeTest fun `set up`() { context = ApplicationProvider.getApplicationContext() @@ -35,7 +101,7 @@ class InternalSentrySdkTest { @Test fun `current scope returns null when hub is no-op`() { - Sentry.setCurrentHub(NoOpHub.getInstance()) + Sentry.getCurrentHub().close() val scope = InternalSentrySdk.getCurrentScope() assertNull(scope) } @@ -134,4 +200,71 @@ class InternalSentrySdkTest { val serializedScope = InternalSentrySdk.serializeScope(context, options, scope) assertTrue(((serializedScope["contexts"] as Map<*, *>)["app"] as Map<*, *>).containsKey("app_name")) } + + @Test + fun `captureEnvelope fails if payload is invalid`() { + assertFails { + InternalSentrySdk.captureEnvelope(ByteArray(8)) + } + } + + @Test + fun `captureEnvelope correctly captures the original envelope data`() { + val fixture = Fixture() + fixture.init(context) + + // when capture envelope is called + fixture.captureEnvelopeWithEvent() + + // then one envelope should be captured + val capturedEnvelopes = fixture.capturedEnvelopes + assertEquals(1, capturedEnvelopes.size) + + val capturedEnvelope = capturedEnvelopes.first() + val capturedEnvelopeItems = capturedEnvelope.items.toList() + + // and it should contain the original event / attachment + assertEquals(1, capturedEnvelopeItems.size) + assertEquals(SentryItemType.Event, capturedEnvelopeItems[0].header.type) + } + + @Test + fun `captureEnvelope correctly enriches the envelope with session data`() { + val fixture = Fixture() + fixture.init(context) + + // when capture envelope is called with an crashed event + fixture.captureEnvelopeWithEvent( + SentryEvent(RuntimeException()).apply { + val mechanism = Mechanism() + mechanism.isHandled = false + + val factory = SentryExceptionFactory(mock()) + val sentryExceptions = factory.getSentryExceptions( + ExceptionMechanismException( + mechanism, + Throwable(), + Thread() + ) + ) + exceptions = sentryExceptions + } + ) + + // then the session should be included + val capturedEnvelope = fixture.capturedEnvelopes.first() + val capturedEnvelopeItems = capturedEnvelope.items.toList() + + // and it should contain the original event / attachment + assertEquals(2, capturedEnvelopeItems.size) + assertEquals(SentryItemType.Event, capturedEnvelopeItems[0].header.type) + assertEquals(SentryItemType.Session, capturedEnvelopeItems[1].header.type) + + val capturedSession = fixture.options.serializer.deserialize( + InputStreamReader(ByteArrayInputStream(capturedEnvelopeItems[1].data)), + Session::class.java + )!! + + assertEquals(Session.State.Crashed, capturedSession.status) + } } From 2860fa1cd086bed0767be0065101bbba56374d92 Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Thu, 13 Jul 2023 09:11:54 +0200 Subject: [PATCH 09/10] Address PR comments --- .../src/main/java/io/sentry/android/core/ContextUtils.java | 2 +- .../src/main/java/io/sentry/android/core/Installation.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/ContextUtils.java b/sentry-android-core/src/main/java/io/sentry/android/core/ContextUtils.java index 2c60b5abf8f..6a0457e50ef 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/ContextUtils.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/ContextUtils.java @@ -35,7 +35,7 @@ static class SideLoadedInfo { private final boolean isSideLoaded; private final @Nullable String installerStore; - public SideLoadedInfo(boolean isSideLoaded, @Nullable String installerStore) { + public SideLoadedInfo(final boolean isSideLoaded, final @Nullable String installerStore) { this.isSideLoaded = isSideLoaded; this.installerStore = installerStore; } diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/Installation.java b/sentry-android-core/src/main/java/io/sentry/android/core/Installation.java index 4ff7a661fa1..460beb938ff 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/Installation.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/Installation.java @@ -8,10 +8,12 @@ import java.io.RandomAccessFile; import java.nio.charset.Charset; import java.util.UUID; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; +@ApiStatus.Internal public final class Installation { @TestOnly static @Nullable String deviceId = null; From 5f44d963fb514090d6c5fcfe7663b3dbc967cb7e Mon Sep 17 00:00:00 2001 From: Markus Hintersteiner Date: Fri, 14 Jul 2023 09:48:20 +0200 Subject: [PATCH 10/10] Improve nullability and java docs --- .../api/sentry-android-core.api | 9 +-- .../sentry/android/core/DeviceInfoUtil.java | 57 ++++++++++++------- .../io/sentry/android/core/Installation.java | 4 +- .../android/core/InternalSentrySdk.java | 24 ++++++-- .../src/main/java/io/sentry/Breadcrumb.java | 3 +- .../main/java/io/sentry/JsonObjectWriter.java | 24 ++++---- .../main/java/io/sentry/JsonSerializable.java | 3 +- .../src/main/java/io/sentry/ObjectWriter.java | 17 +++--- .../io/sentry/ProfilingTransactionData.java | 3 +- .../java/io/sentry/SentryEnvelopeHeader.java | 3 +- .../io/sentry/SentryEnvelopeItemHeader.java | 3 +- .../src/main/java/io/sentry/SentryEvent.java | 3 +- .../main/java/io/sentry/SentryItemType.java | 3 +- .../src/main/java/io/sentry/SentryLevel.java | 3 +- .../main/java/io/sentry/SentryLockReason.java | 3 +- sentry/src/main/java/io/sentry/Session.java | 3 +- .../src/main/java/io/sentry/SpanContext.java | 3 +- sentry/src/main/java/io/sentry/SpanId.java | 3 +- .../src/main/java/io/sentry/SpanStatus.java | 3 +- .../src/main/java/io/sentry/TraceContext.java | 3 +- .../src/main/java/io/sentry/UserFeedback.java | 3 +- .../io/sentry/clientreport/ClientReport.java | 3 +- .../sentry/clientreport/DiscardedEvent.java | 3 +- .../src/main/java/io/sentry/protocol/App.java | 3 +- .../main/java/io/sentry/protocol/Browser.java | 3 +- .../java/io/sentry/protocol/DebugImage.java | 3 +- .../java/io/sentry/protocol/DebugMeta.java | 3 +- .../main/java/io/sentry/protocol/Device.java | 5 +- .../src/main/java/io/sentry/protocol/Geo.java | 3 +- .../src/main/java/io/sentry/protocol/Gpu.java | 3 +- .../io/sentry/protocol/MeasurementValue.java | 3 +- .../java/io/sentry/protocol/Mechanism.java | 3 +- .../main/java/io/sentry/protocol/Message.java | 3 +- .../io/sentry/protocol/OperatingSystem.java | 3 +- .../main/java/io/sentry/protocol/Request.java | 3 +- .../main/java/io/sentry/protocol/SdkInfo.java | 3 +- .../java/io/sentry/protocol/SdkVersion.java | 3 +- .../io/sentry/protocol/SentryException.java | 3 +- .../java/io/sentry/protocol/SentryId.java | 3 +- .../io/sentry/protocol/SentryPackage.java | 3 +- .../io/sentry/protocol/SentryRuntime.java | 3 +- .../java/io/sentry/protocol/SentrySpan.java | 3 +- .../io/sentry/protocol/SentryStackFrame.java | 3 +- .../io/sentry/protocol/SentryStackTrace.java | 3 +- .../java/io/sentry/protocol/SentryThread.java | 3 +- .../io/sentry/protocol/SentryTransaction.java | 3 +- .../io/sentry/protocol/TransactionInfo.java | 3 +- .../main/java/io/sentry/protocol/User.java | 3 +- .../io/sentry/protocol/ViewHierarchy.java | 3 +- .../io/sentry/protocol/ViewHierarchyNode.java | 3 +- .../java/io/sentry/util/MapObjectWriter.java | 27 ++++++++- .../sentry/vendor/gson/stream/JsonWriter.java | 10 ++-- 52 files changed, 201 insertions(+), 105 deletions(-) diff --git a/sentry-android-core/api/sentry-android-core.api b/sentry-android-core/api/sentry-android-core.api index 95e811834f7..c94dea1e5f6 100644 --- a/sentry-android-core/api/sentry-android-core.api +++ b/sentry-android-core/api/sentry-android-core.api @@ -151,14 +151,13 @@ public final class io/sentry/android/core/CurrentActivityIntegration : android/a public fun register (Lio/sentry/IHub;Lio/sentry/SentryOptions;)V } -public class io/sentry/android/core/DeviceInfoUtil { +public final class io/sentry/android/core/DeviceInfoUtil { public fun (Landroid/content/Context;Lio/sentry/android/core/SentryAndroidOptions;)V public fun collectDeviceInformation (ZZ)Lio/sentry/protocol/Device; public static fun getInstance (Landroid/content/Context;Lio/sentry/android/core/SentryAndroidOptions;)Lio/sentry/android/core/DeviceInfoUtil; - public final fun getOperatingSystem ()Lio/sentry/protocol/OperatingSystem; + public fun getOperatingSystem ()Lio/sentry/protocol/OperatingSystem; public fun getSideLoadedInfo ()Lio/sentry/android/core/ContextUtils$SideLoadedInfo; public static fun resetInstance ()V - protected fun retrieveOperatingSystemInformation ()Lio/sentry/protocol/OperatingSystem; } public abstract class io/sentry/android/core/EnvelopeFileObserverIntegration : io/sentry/Integration, java/io/Closeable { @@ -173,10 +172,6 @@ public abstract interface class io/sentry/android/core/IDebugImagesLoader { public abstract fun loadDebugImages ()Ljava/util/List; } -public final class io/sentry/android/core/Installation { - public static fun id (Landroid/content/Context;)Ljava/lang/String; -} - public final class io/sentry/android/core/InternalSentrySdk { public fun ()V public static fun captureEnvelope ([B)Lio/sentry/protocol/SentryId; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/DeviceInfoUtil.java b/sentry-android-core/src/main/java/io/sentry/android/core/DeviceInfoUtil.java index f9f9d40e791..d74a8b1e2d8 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/DeviceInfoUtil.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/DeviceInfoUtil.java @@ -35,7 +35,7 @@ import org.jetbrains.annotations.TestOnly; @ApiStatus.Internal -public class DeviceInfoUtil { +public final class DeviceInfoUtil { @SuppressLint("StaticFieldLeak") private static volatile DeviceInfoUtil instance; @@ -61,7 +61,8 @@ public DeviceInfoUtil( ContextUtils.retrieveSideLoadedInfo(context, options.getLogger(), buildInfoProvider); } - public static @NotNull DeviceInfoUtil getInstance( + @NotNull + public static DeviceInfoUtil getInstance( final @NotNull Context context, final @NotNull SentryAndroidOptions options) { if (instance == null) { synchronized (DeviceInfoUtil.class) { @@ -139,7 +140,8 @@ public Device collectDeviceInformation( return device; } - public final @NotNull OperatingSystem getOperatingSystem() { + @NotNull + public OperatingSystem getOperatingSystem() { return os; } @@ -164,7 +166,8 @@ protected OperatingSystem retrieveOperatingSystemInformation() { return os; } - public @Nullable ContextUtils.SideLoadedInfo getSideLoadedInfo() { + @Nullable + public ContextUtils.SideLoadedInfo getSideLoadedInfo() { return sideLoadedInfo; } @@ -226,6 +229,7 @@ private void setDeviceIO(final @NotNull Device device, final boolean includeDyna } @SuppressWarnings("NewApi") + @NotNull private TimeZone getTimeZone() { if (buildInfoProvider.getSdkInfoVersion() >= Build.VERSION_CODES.N) { LocaleList locales = context.getResources().getConfiguration().getLocales(); @@ -238,7 +242,8 @@ private TimeZone getTimeZone() { } @SuppressWarnings("JdkObsolete") - private @Nullable Date getBootTime() { + @Nullable + private Date getBootTime() { try { // if user changes the clock, will give a wrong answer, consider ACTION_TIME_CHANGED. // currentTimeMillis returns UTC already @@ -249,7 +254,8 @@ private TimeZone getTimeZone() { return null; } - private @Nullable Intent getBatteryIntent() { + @Nullable + private Intent getBatteryIntent() { return context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); } @@ -258,7 +264,8 @@ private TimeZone getTimeZone() { * * @return the device's current battery level (as a percentage of total), or null if unknown */ - private @Nullable Float getBatteryLevel(final @NotNull Intent batteryIntent) { + @Nullable + private Float getBatteryLevel(final @NotNull Intent batteryIntent) { try { int level = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); int scale = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, -1); @@ -281,7 +288,8 @@ private TimeZone getTimeZone() { * * @return whether or not the device is currently plugged in and charging, or null if unknown */ - private @Nullable Boolean isCharging(final @NotNull Intent batteryIntent) { + @Nullable + private Boolean isCharging(final @NotNull Intent batteryIntent) { try { int plugged = batteryIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); return plugged == BatteryManager.BATTERY_PLUGGED_AC @@ -292,7 +300,8 @@ private TimeZone getTimeZone() { } } - private @Nullable Float getBatteryTemperature(final @NotNull Intent batteryIntent) { + @Nullable + private Float getBatteryTemperature(final @NotNull Intent batteryIntent) { try { int temperature = batteryIntent.getIntExtra(EXTRA_TEMPERATURE, -1); if (temperature != -1) { @@ -309,7 +318,8 @@ private TimeZone getTimeZone() { * * @return the device's current screen orientation, or null if unknown */ - private @Nullable Device.DeviceOrientation getOrientation() { + @Nullable + private Device.DeviceOrientation getOrientation() { Device.DeviceOrientation deviceOrientation = null; try { deviceOrientation = @@ -329,7 +339,8 @@ private TimeZone getTimeZone() { } @SuppressWarnings({"ObsoleteSdkInt", "NewApi"}) - private @NotNull Long getMemorySize(final @NotNull ActivityManager.MemoryInfo memInfo) { + @NotNull + private Long getMemorySize(final @NotNull ActivityManager.MemoryInfo memInfo) { if (buildInfoProvider.getSdkInfoVersion() >= Build.VERSION_CODES.JELLY_BEAN) { return memInfo.totalMem; } @@ -342,7 +353,8 @@ private TimeZone getTimeZone() { * * @return the total amount of internal storage, in bytes */ - private @Nullable Long getTotalInternalStorage(final @NotNull StatFs stat) { + @Nullable + private Long getTotalInternalStorage(final @NotNull StatFs stat) { try { long blockSize = getBlockSizeLong(stat); long totalBlocks = getBlockCountLong(stat); @@ -397,7 +409,8 @@ private int getAvailableBlocksDep(final @NotNull StatFs stat) { * * @return the unused amount of internal storage, in bytes */ - private @Nullable Long getUnusedInternalStorage(final @NotNull StatFs stat) { + @Nullable + private Long getUnusedInternalStorage(final @NotNull StatFs stat) { try { long blockSize = getBlockSizeLong(stat); long availableBlocks = getAvailableBlocksLong(stat); @@ -410,7 +423,8 @@ private int getAvailableBlocksDep(final @NotNull StatFs stat) { } } - private @Nullable StatFs getExternalStorageStat(final @Nullable File internalStorage) { + @Nullable + private StatFs getExternalStorageStat(final @Nullable File internalStorage) { if (!isExternalStorageMounted()) { File path = getExternalStorageDep(internalStorage); if (path != null) { // && path.canRead()) { canRead() will read return false @@ -424,7 +438,8 @@ private int getAvailableBlocksDep(final @NotNull StatFs stat) { } @SuppressWarnings({"ObsoleteSdkInt", "NewApi"}) - private @Nullable File[] getExternalFilesDirs() { + @Nullable + private File[] getExternalFilesDirs() { if (buildInfoProvider.getSdkInfoVersion() >= Build.VERSION_CODES.KITKAT) { return context.getExternalFilesDirs(null); } else { @@ -436,7 +451,8 @@ private int getAvailableBlocksDep(final @NotNull StatFs stat) { return null; } - private @Nullable File getExternalStorageDep(final @Nullable File internalStorage) { + @Nullable + private File getExternalStorageDep(final @Nullable File internalStorage) { final @Nullable File[] externalFilesDirs = getExternalFilesDirs(); if (externalFilesDirs != null) { @@ -471,7 +487,8 @@ private int getAvailableBlocksDep(final @NotNull StatFs stat) { * @return the total amount of external storage, in bytes, or null if no external storage is * mounted */ - private @Nullable Long getTotalExternalStorage(final @NotNull StatFs stat) { + @Nullable + private Long getTotalExternalStorage(final @NotNull StatFs stat) { try { final long blockSize = getBlockSizeLong(stat); final long totalBlocks = getBlockCountLong(stat); @@ -495,7 +512,8 @@ private boolean isExternalStorageMounted() { * @return the unused amount of external storage, in bytes, or null if no external storage is * mounted */ - private @Nullable Long getUnusedExternalStorage(final @NotNull StatFs stat) { + @Nullable + private Long getUnusedExternalStorage(final @NotNull StatFs stat) { try { final long blockSize = getBlockSizeLong(stat); final long availableBlocks = getAvailableBlocksLong(stat); @@ -508,7 +526,8 @@ private boolean isExternalStorageMounted() { } } - private @Nullable String getDeviceId() { + @Nullable + private String getDeviceId() { try { return Installation.id(context); } catch (Throwable e) { diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/Installation.java b/sentry-android-core/src/main/java/io/sentry/android/core/Installation.java index 460beb938ff..007bb306cdd 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/Installation.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/Installation.java @@ -8,13 +8,11 @@ import java.io.RandomAccessFile; import java.nio.charset.Charset; import java.util.UUID; -import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; -@ApiStatus.Internal -public final class Installation { +final class Installation { @TestOnly static @Nullable String deviceId = null; @TestOnly static final String INSTALLATION = "INSTALLATION"; diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java b/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java index 02a79105237..bdc9f055e59 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/InternalSentrySdk.java @@ -45,9 +45,21 @@ public static Scope getCurrentScope() { return scopeRef.get(); } + /** + * Serializes the provided scope. Specific data may be back-filled (e.g. device context) if the + * scope itself does not provide it. + * + * @param context Android context + * @param options Sentry Options + * @param scope the scope + * @return a map containing all relevant scope data (user, contexts, tags, extras, fingerprint, + * level, breadcrumbs) + */ @NotNull public static Map serializeScope( - @NotNull Context context, @NotNull SentryAndroidOptions options, @Nullable Scope scope) { + final @NotNull Context context, + final @NotNull SentryAndroidOptions options, + final @Nullable Scope scope) { final @NotNull Map data = new HashMap<>(); if (scope == null) { return data; @@ -70,7 +82,11 @@ public static Map serializeScope( scope.setUser(user); } if (user.getId() == null) { - user.setId(Installation.id(context)); + try { + user.setId(Installation.id(context)); + } catch (RuntimeException e) { + logger.log(SentryLevel.ERROR, "Could not retrieve installation ID", e); + } } // app context @@ -160,8 +176,8 @@ public static SentryId captureEnvelope(final @NotNull byte[] envelopeData) throw @Nullable private static Session updateSession( - @NotNull IHub hub, - @NotNull SentryOptions options, + final @NotNull IHub hub, + final @NotNull SentryOptions options, final @Nullable Session.State status, final boolean crashedOrErrored) { final @NotNull AtomicReference sessionRef = new AtomicReference<>(); diff --git a/sentry/src/main/java/io/sentry/Breadcrumb.java b/sentry/src/main/java/io/sentry/Breadcrumb.java index 4085d901a15..402fd727dd7 100644 --- a/sentry/src/main/java/io/sentry/Breadcrumb.java +++ b/sentry/src/main/java/io/sentry/Breadcrumb.java @@ -561,7 +561,8 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); writer.name(JsonKeys.TIMESTAMP).value(logger, timestamp); if (message != null) { diff --git a/sentry/src/main/java/io/sentry/JsonObjectWriter.java b/sentry/src/main/java/io/sentry/JsonObjectWriter.java index 314a9013aa5..b174ddb4847 100644 --- a/sentry/src/main/java/io/sentry/JsonObjectWriter.java +++ b/sentry/src/main/java/io/sentry/JsonObjectWriter.java @@ -8,10 +8,10 @@ public final class JsonObjectWriter implements ObjectWriter { - private final JsonWriter jsonWriter; - private final JsonObjectSerializer jsonObjectSerializer; + private final @NotNull JsonWriter jsonWriter; + private final @NotNull JsonObjectSerializer jsonObjectSerializer; - public JsonObjectWriter(Writer out, int maxDepth) { + public JsonObjectWriter(final @NotNull Writer out, final int maxDepth) { jsonWriter = new JsonWriter(out); jsonObjectSerializer = new JsonObjectSerializer(maxDepth); } @@ -41,13 +41,13 @@ public JsonObjectWriter endObject() throws IOException { } @Override - public JsonObjectWriter name(String name) throws IOException { + public JsonObjectWriter name(final @NotNull String name) throws IOException { jsonWriter.name(name); return this; } @Override - public JsonObjectWriter value(String value) throws IOException { + public JsonObjectWriter value(final @Nullable String value) throws IOException { jsonWriter.value(value); return this; } @@ -59,31 +59,31 @@ public JsonObjectWriter nullValue() throws IOException { } @Override - public JsonObjectWriter value(boolean value) throws IOException { + public JsonObjectWriter value(final boolean value) throws IOException { jsonWriter.value(value); return this; } @Override - public JsonObjectWriter value(Boolean value) throws IOException { + public JsonObjectWriter value(final @Nullable Boolean value) throws IOException { jsonWriter.value(value); return this; } @Override - public JsonObjectWriter value(double value) throws IOException { + public JsonObjectWriter value(final double value) throws IOException { jsonWriter.value(value); return this; } @Override - public JsonObjectWriter value(long value) throws IOException { + public JsonObjectWriter value(final long value) throws IOException { jsonWriter.value(value); return this; } @Override - public JsonObjectWriter value(Number value) throws IOException { + public JsonObjectWriter value(final @Nullable Number value) throws IOException { jsonWriter.value(value); return this; } @@ -97,13 +97,13 @@ public JsonObjectWriter value(Number value) throws IOException { * @return this writer. */ @Override - public JsonObjectWriter value(@NotNull ILogger logger, @Nullable Object object) + public JsonObjectWriter value(final @NotNull ILogger logger, final @Nullable Object object) throws IOException { jsonObjectSerializer.serialize(this, logger, object); return this; } - public void setIndent(@NotNull final String indent) { + public void setIndent(final @NotNull String indent) { jsonWriter.setIndent(indent); } } diff --git a/sentry/src/main/java/io/sentry/JsonSerializable.java b/sentry/src/main/java/io/sentry/JsonSerializable.java index 7cbc093927b..f63bc92ed86 100644 --- a/sentry/src/main/java/io/sentry/JsonSerializable.java +++ b/sentry/src/main/java/io/sentry/JsonSerializable.java @@ -4,5 +4,6 @@ import org.jetbrains.annotations.NotNull; public interface JsonSerializable { - void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException; + void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException; } diff --git a/sentry/src/main/java/io/sentry/ObjectWriter.java b/sentry/src/main/java/io/sentry/ObjectWriter.java index bab6e507de8..ea8d4e83eac 100644 --- a/sentry/src/main/java/io/sentry/ObjectWriter.java +++ b/sentry/src/main/java/io/sentry/ObjectWriter.java @@ -13,21 +13,22 @@ public interface ObjectWriter { ObjectWriter endObject() throws IOException; - ObjectWriter name(String name) throws IOException; + ObjectWriter name(final @NotNull String name) throws IOException; - ObjectWriter value(String value) throws IOException; + ObjectWriter value(final @Nullable String value) throws IOException; ObjectWriter nullValue() throws IOException; - ObjectWriter value(boolean value) throws IOException; + ObjectWriter value(final boolean value) throws IOException; - ObjectWriter value(Boolean value) throws IOException; + ObjectWriter value(final @Nullable Boolean value) throws IOException; - ObjectWriter value(double value) throws IOException; + ObjectWriter value(final double value) throws IOException; - ObjectWriter value(long value) throws IOException; + ObjectWriter value(final long value) throws IOException; - ObjectWriter value(Number value) throws IOException; + ObjectWriter value(final @Nullable Number value) throws IOException; - ObjectWriter value(@NotNull ILogger logger, @Nullable Object object) throws IOException; + ObjectWriter value(final @NotNull ILogger logger, final @Nullable Object object) + throws IOException; } diff --git a/sentry/src/main/java/io/sentry/ProfilingTransactionData.java b/sentry/src/main/java/io/sentry/ProfilingTransactionData.java index 7717ae481aa..46ba9bba444 100644 --- a/sentry/src/main/java/io/sentry/ProfilingTransactionData.java +++ b/sentry/src/main/java/io/sentry/ProfilingTransactionData.java @@ -144,7 +144,8 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); writer.name(JsonKeys.ID).value(logger, id); writer.name(JsonKeys.TRACE_ID).value(logger, traceId); diff --git a/sentry/src/main/java/io/sentry/SentryEnvelopeHeader.java b/sentry/src/main/java/io/sentry/SentryEnvelopeHeader.java index 1c29aea2443..ceb7e7bdd55 100644 --- a/sentry/src/main/java/io/sentry/SentryEnvelopeHeader.java +++ b/sentry/src/main/java/io/sentry/SentryEnvelopeHeader.java @@ -89,7 +89,8 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); if (eventId != null) { writer.name(JsonKeys.EVENT_ID).value(logger, eventId); diff --git a/sentry/src/main/java/io/sentry/SentryEnvelopeItemHeader.java b/sentry/src/main/java/io/sentry/SentryEnvelopeItemHeader.java index 25ed2172e7e..1ca9a1c8c2f 100644 --- a/sentry/src/main/java/io/sentry/SentryEnvelopeItemHeader.java +++ b/sentry/src/main/java/io/sentry/SentryEnvelopeItemHeader.java @@ -103,7 +103,8 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); if (contentType != null) { writer.name(JsonKeys.CONTENT_TYPE).value(contentType); diff --git a/sentry/src/main/java/io/sentry/SentryEvent.java b/sentry/src/main/java/io/sentry/SentryEvent.java index 2462f60593d..c4bb423aff5 100644 --- a/sentry/src/main/java/io/sentry/SentryEvent.java +++ b/sentry/src/main/java/io/sentry/SentryEvent.java @@ -248,7 +248,8 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); writer.name(JsonKeys.TIMESTAMP).value(logger, timestamp); if (message != null) { diff --git a/sentry/src/main/java/io/sentry/SentryItemType.java b/sentry/src/main/java/io/sentry/SentryItemType.java index a097573ebf2..69b94faa8e9 100644 --- a/sentry/src/main/java/io/sentry/SentryItemType.java +++ b/sentry/src/main/java/io/sentry/SentryItemType.java @@ -54,7 +54,8 @@ public String getItemType() { } @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.value(itemType); } diff --git a/sentry/src/main/java/io/sentry/SentryLevel.java b/sentry/src/main/java/io/sentry/SentryLevel.java index cdaa72fc970..ac179c9831b 100644 --- a/sentry/src/main/java/io/sentry/SentryLevel.java +++ b/sentry/src/main/java/io/sentry/SentryLevel.java @@ -13,7 +13,8 @@ public enum SentryLevel implements JsonSerializable { FATAL; @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.value(name().toLowerCase(Locale.ROOT)); } diff --git a/sentry/src/main/java/io/sentry/SentryLockReason.java b/sentry/src/main/java/io/sentry/SentryLockReason.java index 2c59176bd96..f376317f6b5 100644 --- a/sentry/src/main/java/io/sentry/SentryLockReason.java +++ b/sentry/src/main/java/io/sentry/SentryLockReason.java @@ -117,7 +117,8 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); writer.name(JsonKeys.TYPE).value(type); if (address != null) { diff --git a/sentry/src/main/java/io/sentry/Session.java b/sentry/src/main/java/io/sentry/Session.java index 9f78aed53a3..f118c938496 100644 --- a/sentry/src/main/java/io/sentry/Session.java +++ b/sentry/src/main/java/io/sentry/Session.java @@ -357,7 +357,8 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); if (sessionId != null) { writer.name(JsonKeys.SID).value(sessionId.toString()); diff --git a/sentry/src/main/java/io/sentry/SpanContext.java b/sentry/src/main/java/io/sentry/SpanContext.java index 81ffb826c54..8a68e9d03ef 100644 --- a/sentry/src/main/java/io/sentry/SpanContext.java +++ b/sentry/src/main/java/io/sentry/SpanContext.java @@ -231,7 +231,8 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); writer.name(JsonKeys.TRACE_ID); traceId.serialize(writer, logger); diff --git a/sentry/src/main/java/io/sentry/SpanId.java b/sentry/src/main/java/io/sentry/SpanId.java index 01aa62162e7..7e221775ced 100644 --- a/sentry/src/main/java/io/sentry/SpanId.java +++ b/sentry/src/main/java/io/sentry/SpanId.java @@ -44,7 +44,8 @@ public String toString() { // JsonElementSerializer @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.value(value); } diff --git a/sentry/src/main/java/io/sentry/SpanStatus.java b/sentry/src/main/java/io/sentry/SpanStatus.java index 3fe24494d57..b0b1bf78c8c 100644 --- a/sentry/src/main/java/io/sentry/SpanStatus.java +++ b/sentry/src/main/java/io/sentry/SpanStatus.java @@ -106,7 +106,8 @@ private boolean matches(int httpStatusCode) { // JsonSerializable @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.value(name().toLowerCase(Locale.ROOT)); } diff --git a/sentry/src/main/java/io/sentry/TraceContext.java b/sentry/src/main/java/io/sentry/TraceContext.java index 88bf08905b8..fa3bcfb0c24 100644 --- a/sentry/src/main/java/io/sentry/TraceContext.java +++ b/sentry/src/main/java/io/sentry/TraceContext.java @@ -193,7 +193,8 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); writer.name(TraceContext.JsonKeys.TRACE_ID).value(logger, traceId); writer.name(TraceContext.JsonKeys.PUBLIC_KEY).value(publicKey); diff --git a/sentry/src/main/java/io/sentry/UserFeedback.java b/sentry/src/main/java/io/sentry/UserFeedback.java index 71ea6e857ff..27086188fe9 100644 --- a/sentry/src/main/java/io/sentry/UserFeedback.java +++ b/sentry/src/main/java/io/sentry/UserFeedback.java @@ -147,7 +147,8 @@ public void setUnknown(@Nullable Map unknown) { // JsonSerializable @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); writer.name(JsonKeys.EVENT_ID); eventId.serialize(writer, logger); diff --git a/sentry/src/main/java/io/sentry/clientreport/ClientReport.java b/sentry/src/main/java/io/sentry/clientreport/ClientReport.java index a9703bb183b..ecc507e477f 100644 --- a/sentry/src/main/java/io/sentry/clientreport/ClientReport.java +++ b/sentry/src/main/java/io/sentry/clientreport/ClientReport.java @@ -55,7 +55,8 @@ public void setUnknown(@Nullable Map unknown) { } @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); writer.name(JsonKeys.TIMESTAMP).value(DateUtils.getTimestamp(timestamp)); diff --git a/sentry/src/main/java/io/sentry/clientreport/DiscardedEvent.java b/sentry/src/main/java/io/sentry/clientreport/DiscardedEvent.java index de5cc12a1c0..8fb5da3165f 100644 --- a/sentry/src/main/java/io/sentry/clientreport/DiscardedEvent.java +++ b/sentry/src/main/java/io/sentry/clientreport/DiscardedEvent.java @@ -72,7 +72,8 @@ public void setUnknown(@Nullable Map unknown) { } @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); writer.name(JsonKeys.REASON).value(reason); diff --git a/sentry/src/main/java/io/sentry/protocol/App.java b/sentry/src/main/java/io/sentry/protocol/App.java index c221a60df28..b025d21e7e7 100644 --- a/sentry/src/main/java/io/sentry/protocol/App.java +++ b/sentry/src/main/java/io/sentry/protocol/App.java @@ -184,7 +184,8 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); if (appIdentifier != null) { writer.name(JsonKeys.APP_IDENTIFIER).value(appIdentifier); diff --git a/sentry/src/main/java/io/sentry/protocol/Browser.java b/sentry/src/main/java/io/sentry/protocol/Browser.java index 136c9be2c9e..99fe427c278 100644 --- a/sentry/src/main/java/io/sentry/protocol/Browser.java +++ b/sentry/src/main/java/io/sentry/protocol/Browser.java @@ -81,7 +81,8 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); if (name != null) { writer.name(JsonKeys.NAME).value(name); diff --git a/sentry/src/main/java/io/sentry/protocol/DebugImage.java b/sentry/src/main/java/io/sentry/protocol/DebugImage.java index 00321900f15..d26432033e4 100644 --- a/sentry/src/main/java/io/sentry/protocol/DebugImage.java +++ b/sentry/src/main/java/io/sentry/protocol/DebugImage.java @@ -271,7 +271,8 @@ public void setUnknown(@Nullable Map unknown) { // JsonSerializable @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); if (uuid != null) { writer.name(JsonKeys.UUID).value(uuid); diff --git a/sentry/src/main/java/io/sentry/protocol/DebugMeta.java b/sentry/src/main/java/io/sentry/protocol/DebugMeta.java index b06a9a72439..67a7fa8a775 100644 --- a/sentry/src/main/java/io/sentry/protocol/DebugMeta.java +++ b/sentry/src/main/java/io/sentry/protocol/DebugMeta.java @@ -73,7 +73,8 @@ public void setUnknown(@Nullable Map unknown) { // JsonSerializable @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); if (sdkInfo != null) { writer.name(JsonKeys.SDK_INFO).value(logger, sdkInfo); diff --git a/sentry/src/main/java/io/sentry/protocol/Device.java b/sentry/src/main/java/io/sentry/protocol/Device.java index 88897f1d78e..4f06f749953 100644 --- a/sentry/src/main/java/io/sentry/protocol/Device.java +++ b/sentry/src/main/java/io/sentry/protocol/Device.java @@ -534,7 +534,7 @@ public enum DeviceOrientation implements JsonSerializable { // JsonElementSerializer @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) throws IOException { writer.value(toString().toLowerCase(Locale.ROOT)); } @@ -590,7 +590,8 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); if (name != null) { writer.name(JsonKeys.NAME).value(name); diff --git a/sentry/src/main/java/io/sentry/protocol/Geo.java b/sentry/src/main/java/io/sentry/protocol/Geo.java index 90fd86954e5..fefc340e1be 100644 --- a/sentry/src/main/java/io/sentry/protocol/Geo.java +++ b/sentry/src/main/java/io/sentry/protocol/Geo.java @@ -136,7 +136,8 @@ public void setUnknown(@Nullable Map unknown) { } @Override - public void serialize(@NotNull ObjectWriter writer, ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); if (city != null) { writer.name(JsonKeys.CITY).value(city); diff --git a/sentry/src/main/java/io/sentry/protocol/Gpu.java b/sentry/src/main/java/io/sentry/protocol/Gpu.java index e2a2a83577b..0dfe85f68f9 100644 --- a/sentry/src/main/java/io/sentry/protocol/Gpu.java +++ b/sentry/src/main/java/io/sentry/protocol/Gpu.java @@ -176,7 +176,8 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); if (name != null) { writer.name(JsonKeys.NAME).value(name); diff --git a/sentry/src/main/java/io/sentry/protocol/MeasurementValue.java b/sentry/src/main/java/io/sentry/protocol/MeasurementValue.java index 0aec89acc35..5ba28f41268 100644 --- a/sentry/src/main/java/io/sentry/protocol/MeasurementValue.java +++ b/sentry/src/main/java/io/sentry/protocol/MeasurementValue.java @@ -78,7 +78,8 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); writer.name(JsonKeys.VALUE).value(value); diff --git a/sentry/src/main/java/io/sentry/protocol/Mechanism.java b/sentry/src/main/java/io/sentry/protocol/Mechanism.java index b72d2d7a54f..648aed39c2b 100644 --- a/sentry/src/main/java/io/sentry/protocol/Mechanism.java +++ b/sentry/src/main/java/io/sentry/protocol/Mechanism.java @@ -167,7 +167,8 @@ public void setUnknown(@Nullable Map unknown) { // JsonSerializable @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); if (type != null) { writer.name(JsonKeys.TYPE).value(type); diff --git a/sentry/src/main/java/io/sentry/protocol/Message.java b/sentry/src/main/java/io/sentry/protocol/Message.java index 9ebd0ebeb84..a1c79e21986 100644 --- a/sentry/src/main/java/io/sentry/protocol/Message.java +++ b/sentry/src/main/java/io/sentry/protocol/Message.java @@ -94,7 +94,8 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); if (formatted != null) { writer.name(JsonKeys.FORMATTED).value(formatted); diff --git a/sentry/src/main/java/io/sentry/protocol/OperatingSystem.java b/sentry/src/main/java/io/sentry/protocol/OperatingSystem.java index e4eaea2608f..796a4ea1a0f 100644 --- a/sentry/src/main/java/io/sentry/protocol/OperatingSystem.java +++ b/sentry/src/main/java/io/sentry/protocol/OperatingSystem.java @@ -134,7 +134,8 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); if (name != null) { writer.name(JsonKeys.NAME).value(name); diff --git a/sentry/src/main/java/io/sentry/protocol/Request.java b/sentry/src/main/java/io/sentry/protocol/Request.java index 1a069937153..14f54038444 100644 --- a/sentry/src/main/java/io/sentry/protocol/Request.java +++ b/sentry/src/main/java/io/sentry/protocol/Request.java @@ -277,7 +277,8 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); if (url != null) { writer.name(JsonKeys.URL).value(url); diff --git a/sentry/src/main/java/io/sentry/protocol/SdkInfo.java b/sentry/src/main/java/io/sentry/protocol/SdkInfo.java index 49fe2df0798..ee3ac1eb165 100644 --- a/sentry/src/main/java/io/sentry/protocol/SdkInfo.java +++ b/sentry/src/main/java/io/sentry/protocol/SdkInfo.java @@ -88,7 +88,8 @@ public void setUnknown(@Nullable Map unknown) { // JsonSerializable @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); if (sdkName != null) { writer.name(JsonKeys.SDK_NAME).value(sdkName); diff --git a/sentry/src/main/java/io/sentry/protocol/SdkVersion.java b/sentry/src/main/java/io/sentry/protocol/SdkVersion.java index 1122301e1ce..5dc7aab591f 100644 --- a/sentry/src/main/java/io/sentry/protocol/SdkVersion.java +++ b/sentry/src/main/java/io/sentry/protocol/SdkVersion.java @@ -197,7 +197,8 @@ public void setUnknown(@Nullable Map unknown) { // JsonSerializable @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); writer.name(JsonKeys.NAME).value(name); writer.name(JsonKeys.VERSION).value(version); diff --git a/sentry/src/main/java/io/sentry/protocol/SentryException.java b/sentry/src/main/java/io/sentry/protocol/SentryException.java index 28973334a81..5ee9464a3c4 100644 --- a/sentry/src/main/java/io/sentry/protocol/SentryException.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryException.java @@ -187,7 +187,8 @@ public void setUnknown(@Nullable Map unknown) { // JsonSerializable @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); if (type != null) { writer.name(JsonKeys.TYPE).value(type); diff --git a/sentry/src/main/java/io/sentry/protocol/SentryId.java b/sentry/src/main/java/io/sentry/protocol/SentryId.java index c68a72ac064..c1e5ea1819e 100644 --- a/sentry/src/main/java/io/sentry/protocol/SentryId.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryId.java @@ -73,7 +73,8 @@ public int hashCode() { // JsonSerializable @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.value(toString()); } diff --git a/sentry/src/main/java/io/sentry/protocol/SentryPackage.java b/sentry/src/main/java/io/sentry/protocol/SentryPackage.java index 351ad171916..cea6bb84974 100644 --- a/sentry/src/main/java/io/sentry/protocol/SentryPackage.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryPackage.java @@ -82,7 +82,8 @@ public void setUnknown(@Nullable Map unknown) { // JsonSerializable @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); writer.name(JsonKeys.NAME).value(name); writer.name(JsonKeys.VERSION).value(version); diff --git a/sentry/src/main/java/io/sentry/protocol/SentryRuntime.java b/sentry/src/main/java/io/sentry/protocol/SentryRuntime.java index 5b751a718c3..751e664ae64 100644 --- a/sentry/src/main/java/io/sentry/protocol/SentryRuntime.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryRuntime.java @@ -75,7 +75,8 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); if (name != null) { writer.name(JsonKeys.NAME).value(name); diff --git a/sentry/src/main/java/io/sentry/protocol/SentrySpan.java b/sentry/src/main/java/io/sentry/protocol/SentrySpan.java index 4e73c424954..00e4ee97682 100644 --- a/sentry/src/main/java/io/sentry/protocol/SentrySpan.java +++ b/sentry/src/main/java/io/sentry/protocol/SentrySpan.java @@ -149,7 +149,8 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); writer.name(JsonKeys.START_TIMESTAMP).value(logger, doubleToBigDecimal(startTimestamp)); if (timestamp != null) { diff --git a/sentry/src/main/java/io/sentry/protocol/SentryStackFrame.java b/sentry/src/main/java/io/sentry/protocol/SentryStackFrame.java index a8186a8fb9f..fcb93eb2e8f 100644 --- a/sentry/src/main/java/io/sentry/protocol/SentryStackFrame.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryStackFrame.java @@ -331,7 +331,8 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); if (filename != null) { writer.name(JsonKeys.FILENAME).value(filename); diff --git a/sentry/src/main/java/io/sentry/protocol/SentryStackTrace.java b/sentry/src/main/java/io/sentry/protocol/SentryStackTrace.java index 1bdb1c9d321..bda820ec878 100644 --- a/sentry/src/main/java/io/sentry/protocol/SentryStackTrace.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryStackTrace.java @@ -128,7 +128,8 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); if (frames != null) { writer.name(JsonKeys.FRAMES).value(logger, frames); diff --git a/sentry/src/main/java/io/sentry/protocol/SentryThread.java b/sentry/src/main/java/io/sentry/protocol/SentryThread.java index 3f33284cd8f..1d57e35b10d 100644 --- a/sentry/src/main/java/io/sentry/protocol/SentryThread.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryThread.java @@ -257,7 +257,8 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); if (id != null) { writer.name(JsonKeys.ID).value(id); diff --git a/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java b/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java index 3d8beaa459f..78ccbef6b0a 100644 --- a/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java @@ -181,7 +181,8 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); if (transaction != null) { writer.name(JsonKeys.TRANSACTION).value(transaction); diff --git a/sentry/src/main/java/io/sentry/protocol/TransactionInfo.java b/sentry/src/main/java/io/sentry/protocol/TransactionInfo.java index 4e2f81f7c3f..a081abf50bc 100644 --- a/sentry/src/main/java/io/sentry/protocol/TransactionInfo.java +++ b/sentry/src/main/java/io/sentry/protocol/TransactionInfo.java @@ -31,7 +31,8 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); if (source != null) { writer.name(JsonKeys.SOURCE).value(logger, source); diff --git a/sentry/src/main/java/io/sentry/protocol/User.java b/sentry/src/main/java/io/sentry/protocol/User.java index 5620f0a1e66..1dc6af78118 100644 --- a/sentry/src/main/java/io/sentry/protocol/User.java +++ b/sentry/src/main/java/io/sentry/protocol/User.java @@ -377,7 +377,8 @@ public static final class JsonKeys { } @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); if (email != null) { writer.name(JsonKeys.EMAIL).value(email); diff --git a/sentry/src/main/java/io/sentry/protocol/ViewHierarchy.java b/sentry/src/main/java/io/sentry/protocol/ViewHierarchy.java index b83748df386..412c0130bbd 100644 --- a/sentry/src/main/java/io/sentry/protocol/ViewHierarchy.java +++ b/sentry/src/main/java/io/sentry/protocol/ViewHierarchy.java @@ -42,7 +42,8 @@ public List getWindows() { } @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); if (renderingSystem != null) { writer.name(JsonKeys.RENDERING_SYSTEM).value(renderingSystem); diff --git a/sentry/src/main/java/io/sentry/protocol/ViewHierarchyNode.java b/sentry/src/main/java/io/sentry/protocol/ViewHierarchyNode.java index e2b7f4fe52f..e3067fa3df5 100644 --- a/sentry/src/main/java/io/sentry/protocol/ViewHierarchyNode.java +++ b/sentry/src/main/java/io/sentry/protocol/ViewHierarchyNode.java @@ -145,7 +145,8 @@ public List getChildren() { } @Override - public void serialize(@NotNull ObjectWriter writer, @NotNull ILogger logger) throws IOException { + public void serialize(final @NotNull ObjectWriter writer, final @NotNull ILogger logger) + throws IOException { writer.beginObject(); if (renderingSystem != null) { writer.name(JsonKeys.RENDERING_SYSTEM).value(renderingSystem); diff --git a/sentry/src/main/java/io/sentry/util/MapObjectWriter.java b/sentry/src/main/java/io/sentry/util/MapObjectWriter.java index 9417841ea3d..26f80eddc29 100644 --- a/sentry/src/main/java/io/sentry/util/MapObjectWriter.java +++ b/sentry/src/main/java/io/sentry/util/MapObjectWriter.java @@ -26,15 +26,36 @@ import java.util.UUID; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicIntegerArray; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +@ApiStatus.Internal public final class MapObjectWriter implements ObjectWriter { final @NotNull Map root; /** - * The stack for maintaining the hierarchy and structure Possible elements: Map<>: An Object - * List<>: Array of objects String: The key for the object on top + * The stack for maintaining the hierarchy of a json-like data structure. Possible elements: + * + *
+   * Map: A JSON like object
+   * List: An array of values.
+   * String: The name for the upcoming Map/List
+   * 
+ * + * E.g. consider the following stack: + * + *
+   * | String ("lastName")
+   * | Map (firstName="John")
+   * 
+ * + * Once .value("Doe") is called, the top-most stack-element ("lastName") is popped and the + * key/value pair is stored in top-most stack element. + * + *
+   * | Map (firstName="John", lastName="Doe")
+   * 
*/ final @NotNull ArrayDeque stack; @@ -208,7 +229,7 @@ private void serializeMap(final @NotNull ILogger logger, final @NotNull Map