dimanche 25 mai 2014

Collection personnalisée en Scala sur Android - TraversableFactory se bloque avec NoClassDefFoundError - Stack Overflow


I'm trying to implement a custom collection, so I'm following this post.


Now, the 'bare' code that leads to a crash is this:


object TraversableCollection extends TraversableFactory[TraversableCollection] {
implicit def canBuildFrom[T] : CanBuildFrom[Coll, T, TraversableCollection[T]] = new GenericCanBuildFrom[T]

def newBuilder[T] = new ListBuffer[T].mapResult(x => new TraversableCollection(x:_*))
}

class TraversableCollection[T](seq : T*) extends Traversable[T]
with GenericTraversableTemplate[T, TraversableCollection]
with TraversableLike[T, TraversableCollection[T]] {
override def companion = TraversableCollection
def foreach[U](f: T => U) = seq.foreach(f)
}

My whole implementation is not much more complicated, it's just a collection that wraps an immutable Vector that can move forward and backward over items, storing the index value internally and exposing 'current' item. So essentially - a two-way iterator.


Anyway, the whole implementation (both the skeleton above, and my full implementation) works just fine in REPL (here's a full implementation):


scala> val vec = Vector("Just", "testing", "it")
vec: scala.collection.immutable.Vector[String] = Vector(Just, testing, it)

scala> val t = new TraversableCollection(vec:_*)
t: TraversableCollection[String] = (Just, testing, it)

scala> t.current
res6: String = Just

scala> t.moveForward(2)

scala> t.current
res8: String = it

scala> t.moveBack(1)

scala> t.current
res10: String = testing

Simple and I need it. Here's the problem though: in the Android app, when I get to the point when the collection is created, PathClassLoader starts crashing, then gets to:


this: NoClassDefFoundError 
detailMessage: "scala.collection.generic.TraversableFactory"

and dies with this in the log:


05-16 12:14:35.056: E/AndroidRuntime(575): java.lang.VerifyError: my.package.data.TraversableCollection

Why? Is there anything I can do about it?


Now my temporary solution is to remove the GenericTraversableTemplate and TraversableLike, and leave the Traversable trait. Not perfect, but would kind-of work for now.


Setup:



  • Eclipse from ADT, Scala IDE plugin + AndroidProguardScala plugin


  • Scala 2.10.0-2012-12-05



[EDIT] Proguard related


From my very, very limited knowledge about Proguard, it seems it should be disabled, because the path is commented out in project.properties:


# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt

I tried commenting and uncommenting the line, along with adding this to proguard-project.txt:


-keepnames scala.collection.generic.TraversableFactory

I'm still having the same error no matter what.


[EDIT 2] Still Proguard related


Here's the default configuration that the AndroidProguardScala generates (and which is used when the app crashes):


-injars "F:\adt-bundle-windows-x86_64\eclipse\configuration\org.eclipse.osgi\bundles\373\1\.cp\lib\scala-library.jar"(!META-INF/MANIFEST.MF)
-injars "F:\adt-bundle-windows-x86_64\eclipse\configuration\org.eclipse.osgi\bundles\373\1\.cp\lib\scala-actors.jar"(!META-INF/MANIFEST.MF)
-injars "F:\adt-bundle-windows-x86_64\eclipse\configuration\org.eclipse.osgi\bundles\372\1\.cp\lib\scala-reflect.jar"(!META-INF/MANIFEST.MF)

-outjars "F:\Projects\AndroidScalaProject\proguard_cache\jartender_cache_7212076580182750151.jar"
-injars "F:\Projects\AndroidScalaProject\bin\classes"
-libraryjars "F:\adt-bundle-windows-x86_64\sdk\platforms\android-17\android.jar"
-libraryjars "F:\Projects\AndroidScalaProject\libs\android-support-v4.jar"

-keep public class * extends android.**
-dontwarn **$$anonfun$*
-dontwarn
-dontoptimize
-dontobfuscate
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers

-ignorewarnings
-forceprocessing

-keepattributes Exceptions,InnerClasses,Signature,Deprecated,
SourceFile,LineNumberTable,*Annotation*,EnclosingMethod

-keep public class scala.ScalaObject { *; }
-keep public class scala.Function0, scala.Function1

# Fix for https://issues.scala-lang.org/browse/SI-5397

-keep class scala.collection.SeqLike {
public protected *;
}

# AndroidProguardScala version: 0.0.47.201302150529

-keep class ...
-keep class ... # and a looot of that for anon-functions and classes in the project.
# Here's one that's interesting:
-keep class my.project.data.TraversableCollection {*;}


I'm trying to implement a custom collection, so I'm following this post.


Now, the 'bare' code that leads to a crash is this:


object TraversableCollection extends TraversableFactory[TraversableCollection] {
implicit def canBuildFrom[T] : CanBuildFrom[Coll, T, TraversableCollection[T]] = new GenericCanBuildFrom[T]

def newBuilder[T] = new ListBuffer[T].mapResult(x => new TraversableCollection(x:_*))
}

class TraversableCollection[T](seq : T*) extends Traversable[T]
with GenericTraversableTemplate[T, TraversableCollection]
with TraversableLike[T, TraversableCollection[T]] {
override def companion = TraversableCollection
def foreach[U](f: T => U) = seq.foreach(f)
}

My whole implementation is not much more complicated, it's just a collection that wraps an immutable Vector that can move forward and backward over items, storing the index value internally and exposing 'current' item. So essentially - a two-way iterator.


Anyway, the whole implementation (both the skeleton above, and my full implementation) works just fine in REPL (here's a full implementation):


scala> val vec = Vector("Just", "testing", "it")
vec: scala.collection.immutable.Vector[String] = Vector(Just, testing, it)

scala> val t = new TraversableCollection(vec:_*)
t: TraversableCollection[String] = (Just, testing, it)

scala> t.current
res6: String = Just

scala> t.moveForward(2)

scala> t.current
res8: String = it

scala> t.moveBack(1)

scala> t.current
res10: String = testing

Simple and I need it. Here's the problem though: in the Android app, when I get to the point when the collection is created, PathClassLoader starts crashing, then gets to:


this: NoClassDefFoundError 
detailMessage: "scala.collection.generic.TraversableFactory"

and dies with this in the log:


05-16 12:14:35.056: E/AndroidRuntime(575): java.lang.VerifyError: my.package.data.TraversableCollection

Why? Is there anything I can do about it?


Now my temporary solution is to remove the GenericTraversableTemplate and TraversableLike, and leave the Traversable trait. Not perfect, but would kind-of work for now.


Setup:



  • Eclipse from ADT, Scala IDE plugin + AndroidProguardScala plugin


  • Scala 2.10.0-2012-12-05



[EDIT] Proguard related


From my very, very limited knowledge about Proguard, it seems it should be disabled, because the path is commented out in project.properties:


# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt

I tried commenting and uncommenting the line, along with adding this to proguard-project.txt:


-keepnames scala.collection.generic.TraversableFactory

I'm still having the same error no matter what.


[EDIT 2] Still Proguard related


Here's the default configuration that the AndroidProguardScala generates (and which is used when the app crashes):


-injars "F:\adt-bundle-windows-x86_64\eclipse\configuration\org.eclipse.osgi\bundles\373\1\.cp\lib\scala-library.jar"(!META-INF/MANIFEST.MF)
-injars "F:\adt-bundle-windows-x86_64\eclipse\configuration\org.eclipse.osgi\bundles\373\1\.cp\lib\scala-actors.jar"(!META-INF/MANIFEST.MF)
-injars "F:\adt-bundle-windows-x86_64\eclipse\configuration\org.eclipse.osgi\bundles\372\1\.cp\lib\scala-reflect.jar"(!META-INF/MANIFEST.MF)

-outjars "F:\Projects\AndroidScalaProject\proguard_cache\jartender_cache_7212076580182750151.jar"
-injars "F:\Projects\AndroidScalaProject\bin\classes"
-libraryjars "F:\adt-bundle-windows-x86_64\sdk\platforms\android-17\android.jar"
-libraryjars "F:\Projects\AndroidScalaProject\libs\android-support-v4.jar"

-keep public class * extends android.**
-dontwarn **$$anonfun$*
-dontwarn
-dontoptimize
-dontobfuscate
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers

-ignorewarnings
-forceprocessing

-keepattributes Exceptions,InnerClasses,Signature,Deprecated,
SourceFile,LineNumberTable,*Annotation*,EnclosingMethod

-keep public class scala.ScalaObject { *; }
-keep public class scala.Function0, scala.Function1

# Fix for https://issues.scala-lang.org/browse/SI-5397

-keep class scala.collection.SeqLike {
public protected *;
}

# AndroidProguardScala version: 0.0.47.201302150529

-keep class ...
-keep class ... # and a looot of that for anon-functions and classes in the project.
# Here's one that's interesting:
-keep class my.project.data.TraversableCollection {*;}

0 commentaires:

Enregistrer un commentaire