2016-07-14 13 views
1

Ich versuche Kryo + Chill (com.twitter:chill_2.11:0.8.0 und Scala-Version ist 2.11.8). Der folgende Code funktioniert auf dem Desktop, aber auf Android stürzt er ab. HierTwitter Chill Absturz auf Android

case class TestDogRef(id: Int) 

    case class TestDog(ref: TestDogRef, name: String, friends: Seq[TestDogRef]) 

    class TestHouse[T](val data: Seq[T]) 

    case class TestDogHouse(override val data: Seq[TestDog]) extends TestHouse[TestDog](data) 

    def serialize[A](data: A): Array[Byte] = { 
     val instantiator = new ScalaKryoInstantiator 
     instantiator.setRegistrationRequired(false) 
     val kryo = instantiator.newKryo() 
     val bao = new ByteArrayOutputStream 
     val output = new Output(bao) 
     kryo.writeObject(output, data) 
     output.close() 
     bao.toByteArray 
    } 

    def deserialize[A](ser: Array[Byte], clazz: Class[A]): A = { 
     val instantiator = new ScalaKryoInstantiator 
     instantiator.setRegistrationRequired(false) 
     val kryo = instantiator.newKryo() 
     val input = new Input(new ByteArrayInputStream(ser)) 
     val deserData = kryo.readObject(input, clazz) 
     deserData 
    } 

    override def run(): String = { 
     val orig = TestDogHouse(Seq(TestDog(TestDogRef(4), "Doggy", Seq(TestDogRef(1))))) 
     val serialized = serialize(orig) 
     val deserialized = deserialize(serialized, classOf[TestDogHouse]) 
     deserialized.toString 
    } 

ist der Absturz:

07-14 11:55:42.053 6744-6764/x.y E/AndroidRuntime: FATAL EXCEPTION: GLThread 137 
                      java.lang.ExceptionInInitializerError 
                       at com.twitter.chill.java.PackageRegistrar.all(Unknown Source) 
                       at com.twitter.chill.AllScalaRegistrar.apply(Unknown Source) 
                       at com.twitter.chill.ScalaKryoInstantiator.newKryo(Unknown Source) 
                       at x.y.LibraryTests$KryoWithChillTest$.serialize(Unknown Source) 
                       at x.y.LibraryTests$KryoWithChillTest$.run(Unknown Source) 
                       at x.y.LibraryTests$$anonfun$run$1.apply(Unknown Source) 
                       at x.y.LibraryTests$$anonfun$run$1.apply(Unknown Source) 
                       at scala.collection.immutable.List.foreach(Unknown Source) 
                       at x.y.LibraryTests$.run(Unknown Source) 
                       at x.y.a.a(Unknown Source) 
                       at com.badlogic.gdx.backends.android.j.onSurfaceChanged(Unknown Source) 
                       at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1505) 
                       at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1240) 
                      Caused by: com.esotericsoftware.kryo.KryoException: Error while getting field 'words' of bitSet 
                       at com.twitter.chill.java.BitSetSerializer.<clinit>(Unknown Source) 
                       at com.twitter.chill.java.PackageRegistrar.all(Unknown Source)  
                       at com.twitter.chill.AllScalaRegistrar.apply(Unknown Source)  
                       at com.twitter.chill.ScalaKryoInstantiator.newKryo(Unknown Source)  
                       at x.y.LibraryTests$KryoWithChillTest$.serialize(Unknown Source)  
                       at x.y.LibraryTests$KryoWithChillTest$.run(Unknown Source)  
                       at x.y.LibraryTests$$anonfun$run$1.apply(Unknown Source)  
                       at x.y.LibraryTests$$anonfun$run$1.apply(Unknown Source)  
                       at scala.collection.immutable.List.foreach(Unknown Source)  
                       at x.y.LibraryTests$.run(Unknown Source)  
                       at x.y.a.a(Unknown Source)  
                       at com.badlogic.gdx.backends.android.j.onSurfaceChanged(Unknown Source)  
                       at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1505)  
                       at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1240)  
                      Caused by: java.lang.NoSuchFieldException: words 
                       at java.lang.Class.getDeclaredField(Class.java:631) 
                       at com.twitter.chill.java.BitSetSerializer.<clinit>(Unknown Source)  
                       at com.twitter.chill.java.PackageRegistrar.all(Unknown Source)  
                       at com.twitter.chill.AllScalaRegistrar.apply(Unknown Source)  
                       at com.twitter.chill.ScalaKryoInstantiator.newKryo(Unknown Source)  
                       at x.y.LibraryTests$KryoWithChillTest$.serialize(Unknown Source)  
                       at x.y.LibraryTests$KryoWithChillTest$.run(Unknown Source)  
                       at x.y.LibraryTests$$anonfun$run$1.apply(Unknown Source)  
                       at x.y.LibraryTests$$anonfun$run$1.apply(Unknown Source)  
                       at scala.collection.immutable.List.foreach(Unknown Source)  
                       at x.y.LibraryTests$.run(Unknown Source)  
                       at x.y.a.a(Unknown Source)  
                       at com.badlogic.gdx.backends.android.j.onSurfaceChanged(Unknown Source)  
                       at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1505)  
                       at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1240)  

Ich vermute, dass es wegen der ProGuard ist - etwas entstellt wird oder fallen gelassen, aber ich habe keine Ahnung, was ich sonst noch tun kann.

Relevante proguard Regeln:

-keep class scala.collection.BitSet { *; } 
-keepclassmembers class scala.collection.BitSet { *; } 
-keep class scala.collection.immutable.BitSet { *; } 
-keepclassmembers class scala.collection.immutable.BitSet { *; } 
-keep class scala.collection.BitSetLike { *; } 
-keepclassmembers class scala.collection.BitSetLike { *; } 
-keep class scala.collection.immutable.BitSet.** { *; } 
-keepclassmembers class scala.collection.immutable.BitSet.** { *; } 
-keepnames class scala.** { *; } 

würde ich jede Hilfe dankbar.

Antwort

2

Dieses Problem bezieht sich nicht auf ProGuard. Die Java-Bibliothek chill verfügt über eine BitSetSerializer für java.util.BitSet Klassen, die über Reflektion auf ein Feld (words) zugreifen. Die java.util.BitSet Implementierung, die in Android enthalten ist (abgeleitet vom Apache Harmony Projekt bis hin zu Android 6, Android N basiert auf OpenJDK), hat kein solches Feld und Sie erhalten den Laufzeitfehler wie in der Frage zu sehen.

Wenn Sie den Quellcode der Chill-Scala-Bibliothek betrachten, werden mit Hilfe der ScalaKryoInstantiator auch alle Java-bezogenen Serialisierer registriert. Sie könnten in der Lage sein, das Problem zu umgehen, indem sie eine EmptyScalaKryoInstantiator stattdessen verwenden und Registrierung alle benötigten Serializer:

val instantiator = new EmptyScalaKryoInstantiator 
instantiator.setRegistrationRequired(false) 
val kryo = instantiator.newKryo() 

val col = new ScalaCollectionsRegistrar 
col(kryo) 
ScalaTupleSerialization.register(kryo) 
.... 
// others as needed 

Siehe auch ScalaKryoInstantiator.scala Referenz zu denen Serialisierer zu.

+0

Vielen Dank, Ihre Lösung funktioniert wunderbar^_ ^. – monnef