首页 > 解决方案 > 如何使用自定义类加载器反序列化对象?

问题描述

在一个项目中,我需要使用自定义类加载器扩展标准类加载器。这样做的主要动机是在运行时扩展类路径。(有关此问题的解决方案,请参阅:https ://stackoverflow.com/a/51584718/231397 )。

通过序列化对象

ObjectOutputStream out;
try {
  FileOutputStream fos = new FileOutputStream(filename);
  out = new ObjectOutputStream(fos);
  out.writeObject(object);
}
catch(FileNotFoundException e) {}
catch (IOException e) { }
finally {
  out.close();
}

工作正常,同时通过反序列化对象

Object object = null;
ObjectInputStream in;
try {
  FileInputStream fis = new FileInputStream(filename);
  ObjectInputStream in = new ObjectInputStream(fis);
  object = in.readObject();
}
catch(FileNotFoundException e) {}
catch (ClassNotFoundException e) {}
finally {
  in.close();
}

失败但有ClassNotFoundException异常。原因是调用了标准类加载器,不知道自定义类加载器。

问:使用自定义类加载器反序列化对象的正确方法是什么?

标签: java

解决方案


(注意:在网上搜索了解决方案后,我对自己的问题给出了答案。在网上找到的一些解决方案“几乎正确”:它不适用于内部类)。

解决方案是扩展ObjectInputStream和覆盖该方法resolveClass(ObjectStreamClass) 这可以通过匿名类来完成。然后Class.forName在内部resolveClass使用自定义类加载器。那是

Object object = null;
try {
  FileInputStream fis = new FileInputStream(filename);
  ObjectInputStream in = new ObjectInputStream(fis) {
    @Override
    public Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
      try {
        return Class.forName(desc.getName(), true, customClassLoader);
      } catch (Exception e) { }

      // Fall back (e.g. for primClasses)
      return super.resolveClass(desc);
    }
  };

  object = in.readObject();
}
catch(FileNotFoundException e) {}
catch (ClassNotFoundException e) {}
finally {
  in.close();
}

备注:您可能会找到建议使用的解决方案

customClassLoader.loadClass(desc.getName());

代替

Class.forName(desc.getName(), true, customClassLoader)

虽然这在许多情况下可能有效,但它可能存在问题。例如,我发现它customClassLoader.loadClass(desc.getName())不适用于内部类(可能是由于包 p 中解析为 pAB 或 pA$B 的类 A 的内部类 B 的命名不同)。另请注意,loadClass不初始化类。见https://stackoverflow.com/a/7099453/231397


推荐阅读