ClassNotFoundException during Deserialization of a

2019-07-21 10:10发布

问题:

I was having an issue with deserializing an object. The current project has a plugin-style architecture, so I have jars that contain class files that are loaded at runtime. I was unable to deserialize an object that contained a class that was found in one of those jars, so I wrote a quick test method that gets called mid-stream that just loaded the plugins, instantiates the correct one (the object implements a particular interface so I can identify it via .isAssignableFrom(..) ), serializes it (which happens fine), and then immediately tries to deserialize it.

I still get a 'ClassNotFoundException'.

Stacktrace:

Jul 21, 2014 4:02:11 PM com.newspinrobotics.auth.MainFrame loadPlugins
SEVERE: null
java.lang.ClassNotFoundException: com.newspinrobotics.auth.plugin.tcpserver.TCPServer
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:270)
at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:625)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1612)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1517)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1771)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)
at com.newspinrobotics.auth.MainFrame.loadPlugins(MainFrame.java:79)
at com.newspinrobotics.auth.MainFrame.<init>(MainFrame.java:43)
at com.newspinrobotics.auth.MainFrame$6.run(MainFrame.java:539)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:733)
at java.awt.EventQueue.access$200(EventQueue.java:103)
at java.awt.EventQueue$3.run(EventQueue.java:694)
at java.awt.EventQueue$3.run(EventQueue.java:692)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:703)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)

Now, before you ask. The TCPServer class has no non-serializable fields in it. It has Strings and primitives in it. There is one field that does not fall into those categories but it is marked transient. There is even a no-arg constructor (though that is not needed, correct?). And yes it implements Serializable (the serialization goes fine).

I am confused how the classloader could possibly NOT have it since it instantiates the object only a few lines before it deserializes it.

I do use a custom-made ClassLoader (extends URLClassLoader) to load the jar files at runtime.

I do provide a public static final long serialVersionUID = XXXXXXXL; field.

EDIT:

The Class loader I am referring to extends URLClassLoader. It's located inside a utility class written by another person that upon further inspection actually is not really even a modification (for some reason he felt like extending it and not really doing anything of substance to it). All the utility does is pick apart jar files, and use the URLClassLoader to add the jar files into the URLClassLoader via addURL(..) and also load the classes via loadClass(..). So it does not seem like there's anything nefarious in this utility. I am no ClassLoader ninja however, so I can certainly give further info on it if needed. It's really just a few utility functions for loading Jar files and picking out class files and loading them.

Help me StackOverflow, you're my only hope (maybe).

回答1:

Did you subclass ObjectInputStream to override resolveClass() to use your custom Classloader? (For an example of someone else doing this, though not a direct answer to your question, see ObjectInputStream custom classloader deserialization issue: resolveClass() not called.)