2016-07-14 6 views
1

Я пытаюсь Kryo + Chill (com.twitter:chill_2.11:0.8.0 и версия Scala 2.11.8). Следующий код работает отлично на рабочем столе, но на Android он падает.Twitter Chill crashing на 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 
    } 

Вот авария:

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)  

Я подозреваю, что это из-за ProGuard - что-то будет искажено или выбросить, но я понятия не имею, что еще я могу сделать.

Соответствующие правила Proguard:

-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.** { *; } 

Я был бы признателен за любую помощь.

ответ

2

Эта проблема не связана с ProGuard. В java-библиотеке chill есть BitSetSerializer для классов java.util.BitSet, которые обращаются к полю (с именем words) через отражение. Теперь реализация java.util.BitSet, которая включена в Android (полученная от проекта Apache Harmony до Android 6, Android N будет основана на OpenJDK), не имеет такого поля, и вы получите ошибку времени выполнения, как видно в вопросе.

Глядя на исходный код библиотеки chill-scala, используя ScalaKryoInstantiator, также регистрируются все связанные с Java сериализаторы. Вы можете быть в состоянии обойти проблему, используя EmptyScalaKryoInstantiator вместо и регистрации всех необходимых сериализаторы:

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

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

Смотрите также ScalaKryoInstantiator.scala для справки, которые сериализаторов включить.

+0

Спасибо, ваше решение работает чудесно^_ ^. – monnef

 Смежные вопросы

  • Нет связанных вопросов^_^