首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >反序列化抛出Scala2.10中的“ClassNotFoundException:JavaConversion$SeqWrapper”

反序列化抛出Scala2.10中的“ClassNotFoundException:JavaConversion$SeqWrapper”
EN

Stack Overflow用户
提问于 2013-06-22 09:15:58
回答 4查看 1.6K关注 0票数 1

我有一个从Scala-2.9序列化出来的相当复杂的对象图,我需要将它读入Scala-2.10。然而,在对象图的某处,Scala-2.10抛出了:

代码语言:javascript
复制
! java.lang.ClassNotFoundException: scala.collection.JavaConversions$SeqWrapper
! at java.net.URLClassLoader$1.run(URLClassLoader.java:366) ~[na:1.7.0_21]
! at java.net.URLClassLoader$1.run(URLClassLoader.java:355) ~[na:1.7.0_21]
! at java.security.AccessController.doPrivileged(Native Method) ~[na:1.7.0_21]
! at java.net.URLClassLoader.findClass(URLClassLoader.java:354) ~[na:1.7.0_21]
! at java.lang.ClassLoader.loadClass(ClassLoader.java:423) ~[na:1.7.0_21]
! at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) ~[na:1.7.0_21]
! at java.lang.ClassLoader.loadClass(ClassLoader.java:356) ~[na:1.7.0_21]
! at java.lang.Class.forName0(Native Method) ~[na:1.7.0_21]
! at java.lang.Class.forName(Class.java:266) ~[na:1.7.0_21]
! at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:623) ~[na:1.7.0_21]
...

将这个序列化对象加载到Scala-2.10中最简单的方法是什么?使用Scala-2.9可以正确地对对象进行反序列化,但看起来在标准库中发生了变化。scala.collection.JavaConversions的大多数成员现在都在scala.collection.convert.Wrappers

展望未来,我还对持久化大型复杂对象图的更健壮的方法感兴趣,而不必显式地为所涉及的每个类指定序列化。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-06-30 05:01:52

所以,这就是最终为我工作的方法,感谢@som snytt为我指明了正确的方向:

代码语言:javascript
复制
object MyWrappers {
  import java.{ lang => jl, util => ju }, java.util.{ concurrent => juc }
  import scala.collection.convert._
  import WrapAsScala._
  import WrapAsJava._
  import Wrapper._

  @SerialVersionUID(3200663006510408715L)
  case class SeqWrapper[A](underlying: Seq[A]) extends ju.AbstractList[A] with Wrappers.IterableWrapperTrait[A] {
    def get(i: Int) = underlying(i)
  }
}

import org.apache.commons.io.input.ClassLoaderObjectInputStream
object Loader extends ClassLoader {
  override def loadClass(name: String) : Class[_] = {
    import javassist._
    try super.loadClass(name)
    catch {
      case e: ClassNotFoundException if name.startsWith("scala.collection.JavaConversions") => {
            val name2 = name.replaceFirst("scala.collection.JavaConversions",
                                          "MyWrappers")
            val cls = ClassPool.getDefault().getAndRename(name2, name)
            cls.toClass()
          }
    }
  }
}

val objectStream = new ClassLoaderObjectInputStream(Loader, stream)
objectStream.readObject()

这允许我将原始的2.9序列化文件直接读入2.10,而无需重新序列化。它依赖Javassist来实现类的间接寻址,并使用来自Apache Commons的ClassLoaderObjectStream,尽管这可以很容易地实现您自己的。我不是很高兴不得不制作自己的SeqWrapper副本(这是我的文件中唯一有问题的类),但是scala-2.10的scala.collection.convert.Wrappers中的包装类与2.9的scala.collection.JavaConversions中的相应类具有不同的SerialVersionUID,尽管它们的源代码在文本上是相同的。我最初尝试只重定向到scala.collection.convert.Wrappers,并使用Javassist设置SerialVersionUID:

代码语言:javascript
复制
object Loader extends ClassLoader {
  override def loadClass(name: String) : Class[_] = {
    import javassist._
    try super.loadClass(name)
    catch {
      case e: ClassNotFoundException if name.startsWith("scala.collection.JavaConversions") => {
            val name2 = name.replaceFirst("JavaConversions", "convert.Wrappers")
            val cls = ClassPool.getDefault().getAndRename(name2, name)
            cls.addField(CtField.make("private static final long serialVersionUID = 3200663006510408715L;", cls))
            cls.toClass()
          }
    }
  }
}

这允许我无异常地读取序列化文件,但以这种方式读取的对象是不完整的。(如果这种方法有效,并且文件中有多个问题类,我真的需要SerialVersionUID的查找表,但这不是重点)。如果有人知道一种方法,在不破坏任何其他东西的情况下在Javassist生成的类上设置SerialVersionUID,我很乐意听到。

票数 0
EN

Stack Overflow用户

发布于 2013-06-25 00:16:31

想法,没有真正的帮助:

Scala

  • 您遇到了Scala集合底层实现的变化,这反映在Scala集合的序列化中。你不能在2.10中“直接加载”它,所以你需要一些共同点。

  • 你可能会在每个版本的Scala中遇到这个问题,因为集合还没有完全确定。

  • 我假设你的意图是使用基于2.9的代码加载你的图形,转换成一些新的格式,然后转储成新的“通用”格式。

  • 在java世界,我会使用JAXB或SDO;也许是EclipseLink MOXy。我怀疑MOXy是否知道Scala集合类型。

  • 我想您已经看到过将对象图转换为完全基于核心

数据类型的东西--

票数 2
EN

Stack Overflow用户

发布于 2013-06-27 06:25:04

请不要下意识地反对,但我的想法是在一个类加载器(在scala 2.9上)中反序列化,转换成一个java集合,然后在第二个类加载器(类路径上有2.10 )中从java转换回scala。

换句话说,java是通用格式( java运行时对两个类加载器都是通用的)。

(或者,不使用两个类加载器,而是尝试序列化java表单,然后再将其还原。)

我认为这是Richard的第6条,它不一定要完全是java内核,只需要兼容的就行了。

我将尝试在喝咖啡休息时提供一个示例,但当然需要注意的是,不兼容性取决于收集的内容,而不是收集的内容。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17246409

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档