1

Scala-2.9 からシリアル化されたかなり複雑なオブジェクト グラフがあり、それを Scala-2.10 に読み込む必要があります。ただし、オブジェクト グラフのどこかで Scala-2.10 がスローします。

! 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

今後は、関連するすべてのクラスのシリアル化を明示的に指定することなく、大規模で複雑なオブジェクト グラフを永続化する、より堅牢な方法にも関心があります。

4

4 に答える 4

2

本当の助けにはならない考え:

  1. 同じのシリアル化に反映されている Scala コレクションの基になる実装の変更にぶつかりました。2.10 に「そのままロードする」ことはできないため、いくつかの共通点が必要です。

  2. Collections が完全に解決されていないため、Scala のすべてのバージョンでこれに遭遇する可能性があります。

  3. あなたの意図は、2.9 ベースのコードを使用してグラフをロードし、新しい形式に変換し、新しい「共通」形式でダンプすることだと思います。

  4. Java の世界では、JAXB または SDO に手を伸ばします。おそらくEclipseLink MOXy。MOXy が Scala のコレクション型を認識しているとは思えません。

  5. これはもう見たことがあると思います。

  6. オブジェクト グラフを、コア Java データ型に完全に基づくものに変換できますか?

于 2013-06-24T16:16:31.087 に答える
0

だから、@som-snyttが正しい方向に向けてくれたおかげで、私のために働いたのは次のとおりです。

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' の対応するクラスとは異なる SerialVersionUID を持っています。ソースがテキスト的に同一でscala.collection.JavaConversionsあるにもかかわらず。私は当初、scala.collection.convert.Wrappers にリダイレクトして、Javassist で SerialVersionUID を設定しようとしました。

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 を設定する方法を誰かが知っていれば、他の何かを壊すことなく、それを聞きたいと思います。

于 2013-06-29T21:01:52.153 に答える
0

これはおそらくあなたの顔に吹き飛ばされますが、2.10 scala-library.jar の後に 2.9 scala-library.jar をクラスパスに配置してみてください。次に、クラスローダーが見つける必要があります

 scala.collection.JavaConversions$SeqWrapper

、でも連載がここまで進んだらビックリ…

gson、jackson、lift-json などを使用して json にシリアル化することを検討する必要があります。面倒ですが、一度やれば完了です。他の言語でも機能します。「迅速な」解決策は、今後も繰り返し痛みを伴うことを意味します...

幸運を!

ルベン

于 2013-06-26T15:23:01.697 に答える