【问题标题】:ClassNotFoundException during Deserialization of a just-serializaed class刚刚序列化的类的反序列化期间的 ClassNotFoundException
【发布时间】:2014-07-21 20:41:01
【问题描述】:

我在反序列化对象时遇到问题。当前项目具有插件式架构,因此我有包含在运行时加载的类文件的 jar。我无法反序列化包含在其中一个 jar 中找到的类的对象,因此我编写了一个快速测试方法,该方法被称为中流,它刚刚加载了插件,实例化了正确的(对象实现了特定的接口所以我可以通过 .isAssignableFrom(..) 识别它,序列化它(这很好),然后立即尝试反序列化它。

我仍然收到“ClassNotFoundException”。

堆栈跟踪:

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)

现在,在你问之前。 TCPServer 类中没有不可序列化的字段。它有字符串和原语。有一个字段不属于这些类别,但它被标记为瞬态。甚至还有一个无参数的构造函数(虽然 不需要,对吗?)。是的,它实现了 Serializable (序列化很好)。

我很困惑类加载器怎么可能没有它,因为它在反序列化之前仅实例化对象几行。

我确实使用定制的 ClassLoader(扩展 URLClassLoader)在运行时加载 jar 文件。

我确实提供了一个 public static final long serialVersionUID = XXXXXXXL;字段。

编辑:

我所指的类加载器扩展了 URLClassLoader。它位于另一个人编写的实用程序类中,经过进一步检查,实际上甚至不是真正的修改(出于某种原因,他想扩展它而不是真正对其做任何实质性的事情)。该实用程序所做的只是挑选 jar 文件,并使用 URLClassLoader 通过 addURL(..) 将 jar 文件添加到 URLClassLoader 中,并通过 loadClass(..) 加载类。因此,该实用程序似乎没有任何恶意。但是,我不是 ClassLoader 忍者,因此如果需要,我当然可以提供更多信息。它实际上只是一些用于加载 Jar 文件和挑选类文件并加载它们的实用函数。

帮助我 StackOverflow,你是我唯一的希望(也许)。

【问题讨论】:

  • 所以你已经实现了一个自定义 ClassLoader,你遇到了类加载问题,并且你没有发布任何类加载代码(自定义 ClassLoader 和使用它,包括首先构建 TCPServer 对象的代码)...
  • 好吧。考虑到 ClassLoader 似乎可以用于实例化对象(以使它们完全可用的方式),问题似乎不在类加载器中。
  • 您的自定义类加载器似乎不在您的堆栈跟踪中,这使得它在您反序列化时看起来好像没有被使用。因此,尽管它可能很好,但尝试使用它的代码(通过 ObjectInputStream)似乎不是。能发下相关代码吗?
  • 你认为什么是相关的?整个类加载器实用程序?或者“修改后的类加载器”的定义最终根本没有被修改。它已扩展,但仅覆盖 addURL 并在其中简单地调用 super。所以根本没有真正扩展。
  • 我不太关心 ClassLoader 本身(因为正如您所说,它可以在其他地方工作),而更多地关注您调用它的代码。因此,如果我们关于在我的答案的 cmets 中扩展 ObjectInputStream 的讨论没有取得成果,我建议您发布您从类加载器成功实例化 TCPServer 的代码,以及您在其中的代码'从ObjectInputStream 反序列化它失败(包括你实例化和配置ObjectInputStream 的代码)。但希望扩展 ObjectInputStream 将是您所需要的。

标签: java serialization deserialization classloader classnotfoundexception


【解决方案1】:

您是否继承了ObjectInputStream 以覆盖resolveClass() 以使用您的自定义Classloader? (有关其他人这样做的示例,尽管不是您问题的直接答案,请参阅ObjectInputStream custom classloader deserialization issue: resolveClass() not called。)

【讨论】:

  • 不,我没有继承 ObjectInputStream,我只是使用了默认值。我根本没有考虑过这种互动。
  • 我自己没有这样做,但我做的少量谷歌搜索似乎表明这是最常见的做法。 (可能还有其他方法可以做到这一点,我不确定。)我的猜测是标准ObjectInputStream 只是调用标准类加载器,让您无法在调用中间注入自定义类加载器。我有点惊讶没有用于将一组自定义 ClassLoaders 传递给标准 ObjectInputStream 的 API,但也许将来会出现。
  • 对不起。忘记点击了。是的,这是一个类加载器问题。它需要制作一个自定义的 ObjectInputStream 来修复它。
  • 嗨,@AaronMarcus,您是如何以及在哪里实现这个自定义 ObjectInputStream 的?我们在这里面临完全相同的问题:stackoverflow.com/questions/66663334/…
猜你喜欢
  • 1970-01-01
  • 2011-10-18
  • 1970-01-01
  • 1970-01-01
  • 2014-08-22
  • 2016-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多