Skip to content

Commit fb98d56

Browse files
authored
Fallback to using ThrowableModel if serializing exception to bytes fails (#2334)
1 parent b2c3b76 commit fb98d56

File tree

1 file changed

+32
-22
lines changed

1 file changed

+32
-22
lines changed
Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import java.io.InputStream
1616
import java.io.ObjectInputStream
1717
import java.io.ObjectOutputStream
1818
import java.io.ObjectStreamClass
19-
import java.lang.RuntimeException
2019

2120
class ThrowableSerializer : Serializer<Throwable>() {
2221
companion object {
@@ -29,7 +28,7 @@ class ThrowableSerializer : Serializer<Throwable>() {
2928
val message: String?,
3029
val stackTrace: Array<StackTraceElement>,
3130
val cause: ThrowableModel?,
32-
val serializedException: ByteArray,
31+
val serializedExceptionBytes: ByteArray?,
3332
)
3433

3534
override fun write(kryo: Kryo, output: Output, throwable: Throwable?) {
@@ -38,33 +37,44 @@ class ThrowableSerializer : Serializer<Throwable>() {
3837
message = message,
3938
stackTrace = stackTrace,
4039
cause = cause?.toModel(),
41-
serializedException = ByteArrayOutputStream().use { byteOutputStream ->
42-
val objectOutputStream = ObjectOutputStream(byteOutputStream)
43-
objectOutputStream.writeObject(this)
44-
objectOutputStream.flush()
45-
byteOutputStream.toByteArray()
40+
serializedExceptionBytes = try {
41+
ByteArrayOutputStream().use { byteOutputStream ->
42+
val objectOutputStream = ObjectOutputStream(byteOutputStream)
43+
objectOutputStream.writeObject(this)
44+
objectOutputStream.flush()
45+
byteOutputStream.toByteArray()
46+
}
47+
} catch (e: Throwable) {
48+
if (loggedUnserializableExceptionClassIds.add(this::class.java.id)) {
49+
logger.warn { "Failed to serialize ${this::class.java.id} to bytes, cause: $e" }
50+
logger.warn { "Constructing ThrowableModel with serializedExceptionBytes = null" }
51+
}
52+
null
4653
}
4754
)
4855
kryo.writeObject(output, throwable?.toModel())
4956
}
5057

5158
override fun read(kryo: Kryo, input: Input, type: Class<out Throwable>): Throwable? {
52-
fun ThrowableModel.toThrowable(): Throwable = try {
53-
ByteArrayInputStream(this.serializedException).use { byteInputStream ->
54-
val objectInputStream = IgnoringUidWrappingObjectInputStream(byteInputStream, kryo.classLoader)
55-
objectInputStream.readObject() as Throwable
56-
}
57-
} catch (e: Throwable) {
58-
if (loggedUnserializableExceptionClassIds.add(this.classId)) {
59-
logger.warn { "Failed to deserialize ${this.classId} from bytes, cause: $e" }
60-
logger.warn { "Falling back to constructing throwable instance from ThrowableModel" }
59+
fun ThrowableModel.toThrowable(): Throwable {
60+
val throwableFromBytes = this.serializedExceptionBytes?.let { bytes ->
61+
try {
62+
ByteArrayInputStream(bytes).use { byteInputStream ->
63+
val objectInputStream = IgnoringUidWrappingObjectInputStream(byteInputStream, kryo.classLoader)
64+
objectInputStream.readObject() as Throwable
65+
}
66+
} catch (e: Throwable) {
67+
if (loggedUnserializableExceptionClassIds.add(this.classId)) {
68+
logger.warn { "Failed to deserialize ${this.classId} from bytes, cause: $e" }
69+
logger.warn { "Falling back to constructing throwable instance from ThrowableModel" }
70+
}
71+
null
72+
}
6173
}
62-
63-
val cause = cause?.toThrowable()
64-
when {
65-
RuntimeException::class.java.isAssignableFrom(classId.jClass) -> RuntimeException(message, cause)
66-
Error::class.java.isAssignableFrom(classId.jClass) -> Error(message, cause)
67-
else -> Exception(message, cause)
74+
return throwableFromBytes ?: when {
75+
RuntimeException::class.java.isAssignableFrom(classId.jClass) -> RuntimeException(message, cause?.toThrowable())
76+
Error::class.java.isAssignableFrom(classId.jClass) -> Error(message, cause?.toThrowable())
77+
else -> Exception(message, cause?.toThrowable())
6878
}.also {
6979
it.stackTrace = stackTrace
7080
}

0 commit comments

Comments
 (0)