Skip to content

Commit 572d0cb

Browse files
committed
Disable automatically when reflection fails.
1 parent b349b77 commit 572d0cb

File tree

1 file changed

+66
-51
lines changed

1 file changed

+66
-51
lines changed

core/src/main/scala/org/apache/spark/serializer/SerializationDebugger.scala

Lines changed: 66 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,18 @@ import java.security.AccessController
2424
import scala.annotation.tailrec
2525
import scala.collection.mutable
2626

27+
import org.apache.spark.Logging
2728

28-
private[serializer] object SerializationDebugger {
29+
private[serializer] object SerializationDebugger extends Logging {
2930

3031
/**
3132
* Improve the given NotSerializableException with the serialization path leading from the given
3233
* object to the problematic object.
3334
*/
3435
def improveException(obj: Any, e: NotSerializableException): NotSerializableException = {
35-
if (enableDebugging) {
36+
if (enableDebugging && reflect != null) {
3637
new NotSerializableException(
37-
e.getMessage + "\nSerialization stack:\n" + find(obj).map("\t-" + _).mkString("\n"))
38+
e.getMessage + "\nSerialization stack:\n" + find(obj).map("\t- " + _).mkString("\n"))
3839
} else {
3940
e
4041
}
@@ -213,79 +214,93 @@ private[serializer] object SerializationDebugger {
213214
/** An implicit class that allows us to call private methods of ObjectStreamClass. */
214215
implicit class ObjectStreamClassMethods(val desc: ObjectStreamClass) extends AnyVal {
215216
def getSlotDescs: Array[ObjectStreamClass] = {
216-
objectStreamClassGetClassDataLayout.invoke(desc).asInstanceOf[Array[Object]].map {
217-
classDataSlot => classDataSlotDesc.get(classDataSlot).asInstanceOf[ObjectStreamClass]
217+
reflect.GetClassDataLayout.invoke(desc).asInstanceOf[Array[Object]].map {
218+
classDataSlot => reflect.DescField.get(classDataSlot).asInstanceOf[ObjectStreamClass]
218219
}
219220
}
220221

221222
def hasWriteObjectMethod: Boolean = {
222-
objectStreamClassHasWriteObjectMethod.invoke(desc).asInstanceOf[Boolean]
223+
reflect.HasWriteObjectMethod.invoke(desc).asInstanceOf[Boolean]
223224
}
224225

225226
def hasWriteReplaceMethod: Boolean = {
226-
objectStreamClassHasWriteReplaceMethod.invoke(desc).asInstanceOf[Boolean]
227+
reflect.HasWriteReplaceMethod.invoke(desc).asInstanceOf[Boolean]
227228
}
228229

229230
def invokeWriteReplace(obj: Object): Object = {
230-
objectStreamClassInvokeWriteReplace.invoke(desc, obj)
231+
reflect.InvokeWriteReplace.invoke(desc, obj)
231232
}
232233

233234
def getNumObjFields: Int = {
234-
objectStreamClassGetNumObjFields.invoke(desc).asInstanceOf[Int]
235+
reflect.GetNumObjFields.invoke(desc).asInstanceOf[Int]
235236
}
236237

237238
def getObjFieldValues(obj: Object, out: Array[Object]): Unit = {
238-
objectStreamClassGetObjFieldValues.invoke(desc, obj, out)
239+
reflect.GetObjFieldValues.invoke(desc, obj, out)
239240
}
240241
}
241242

242-
/** ObjectStreamClass.getClassDataLayout */
243-
private val objectStreamClassGetClassDataLayout: Method = {
244-
val f = classOf[ObjectStreamClass].getDeclaredMethod("getClassDataLayout")
245-
f.setAccessible(true)
246-
f
243+
/**
244+
* Object to hold all the reflection objects. If we run on a JVM that we cannot understand,
245+
* this field will be null and this the debug helper should be disabled.
246+
*/
247+
private val reflect: ObjectStreamClassReflection = try {
248+
new ObjectStreamClassReflection
249+
} catch {
250+
case e: Exception =>
251+
logWarning("Cannot find private methods using reflection", e)
252+
null
247253
}
248254

249-
/** ObjectStreamClass.hasWriteObjectMethod */
250-
private val objectStreamClassHasWriteObjectMethod: Method = {
251-
val f = classOf[ObjectStreamClass].getDeclaredMethod("hasWriteObjectMethod")
252-
f.setAccessible(true)
253-
f
254-
}
255+
private class ObjectStreamClassReflection {
256+
/** ObjectStreamClass.getClassDataLayout */
257+
val GetClassDataLayout: Method = {
258+
val f = classOf[ObjectStreamClass].getDeclaredMethod("getClassDataLayout")
259+
f.setAccessible(true)
260+
f
261+
}
255262

256-
/** ObjectStreamClass.hasWriteReplaceMethod */
257-
private val objectStreamClassHasWriteReplaceMethod: Method = {
258-
val f = classOf[ObjectStreamClass].getDeclaredMethod("hasWriteReplaceMethod")
259-
f.setAccessible(true)
260-
f
261-
}
263+
/** ObjectStreamClass.hasWriteObjectMethod */
264+
val HasWriteObjectMethod: Method = {
265+
val f = classOf[ObjectStreamClass].getDeclaredMethod("hasWriteObjectMethod")
266+
f.setAccessible(true)
267+
f
268+
}
262269

263-
/** ObjectStreamClass.invokeWriteReplace */
264-
private val objectStreamClassInvokeWriteReplace: Method = {
265-
val f = classOf[ObjectStreamClass].getDeclaredMethod("invokeWriteReplace", classOf[Object])
266-
f.setAccessible(true)
267-
f
268-
}
270+
/** ObjectStreamClass.hasWriteReplaceMethod */
271+
val HasWriteReplaceMethod: Method = {
272+
val f = classOf[ObjectStreamClass].getDeclaredMethod("hasWriteReplaceMethod")
273+
f.setAccessible(true)
274+
f
275+
}
269276

270-
/** ObjectStreamClass.getNumObjFields */
271-
private val objectStreamClassGetNumObjFields: Method = {
272-
val f = classOf[ObjectStreamClass].getDeclaredMethod("getNumObjFields")
273-
f.setAccessible(true)
274-
f
275-
}
277+
/** ObjectStreamClass.invokeWriteReplace */
278+
val InvokeWriteReplace: Method = {
279+
val f = classOf[ObjectStreamClass].getDeclaredMethod("invokeWriteReplace", classOf[Object])
280+
f.setAccessible(true)
281+
f
282+
}
276283

277-
/** ObjectStreamClass.getObjFieldValues */
278-
private val objectStreamClassGetObjFieldValues: Method = {
279-
val f = classOf[ObjectStreamClass].getDeclaredMethod(
280-
"getObjFieldValues", classOf[Object], classOf[Array[Object]])
281-
f.setAccessible(true)
282-
f
283-
}
284+
/** ObjectStreamClass.getNumObjFields */
285+
val GetNumObjFields: Method = {
286+
val f = classOf[ObjectStreamClass].getDeclaredMethod("getNumObjFields")
287+
f.setAccessible(true)
288+
f
289+
}
284290

285-
/** ObjectStreamClass$ClassDataSlot.desc field */
286-
private val classDataSlotDesc: Field = {
287-
val f = Class.forName("java.io.ObjectStreamClass$ClassDataSlot").getDeclaredField("desc")
288-
f.setAccessible(true)
289-
f
291+
/** ObjectStreamClass.getObjFieldValues */
292+
val GetObjFieldValues: Method = {
293+
val f = classOf[ObjectStreamClass].getDeclaredMethod(
294+
"getObjFieldValues", classOf[Object], classOf[Array[Object]])
295+
f.setAccessible(true)
296+
f
297+
}
298+
299+
/** ObjectStreamClass$ClassDataSlot.desc field */
300+
val DescField: Field = {
301+
val f = Class.forName("java.io.ObjectStreamClass$ClassDataSlot").getDeclaredField("desc")
302+
f.setAccessible(true)
303+
f
304+
}
290305
}
291306
}

0 commit comments

Comments
 (0)