@@ -24,17 +24,18 @@ import java.security.AccessController
2424import scala .annotation .tailrec
2525import 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 + " \n Serialization stack:\n " + find(obj).map(" \t -" + _).mkString(" \n " ))
38+ e.getMessage + " \n Serialization 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