ProGuard configuration breaks serialization #122

Open
pimlott opened this Issue Mar 23, 2012 · 4 comments

Comments

Projects
None yet
3 participants
@pimlott

pimlott commented Mar 23, 2012

The default ProGuard configuration in src/main/scala/AndroidInstall.scala is missing many of the suggested configurations in the ProGuard documentation (http://proguard.sourceforge.net/index.html#manual/examples.html), including those for serializable classes. For example, if my class relies on a readResolve method for deserialization, that method is stripped ProGuard and so deserialization breaks.

I suggest putting a more complete and conservative ProGuard configuration in sbt-android-plugin by default. I'm still learning, so I don't have a full proposal, but I would include at least:

-keepclassmembers class * implements java.io.Serializable {
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}

It may be worth centrally maintaining a ProGuard configuration that works reliably for the Scala library.

@rst

This comment has been minimized.

Show comment
Hide comment
@rst

rst May 18, 2012

FWIW, this can be worked around by adding the text suggested above to the
build settings in a project's build.scala. roughly like so:

lazy val fullAndroidSettings =
General.settings ++
AndroidProject.androidSettings ++
TypedResources.settings ++
AndroidMarketPublish.settings ++ Seq (
keyalias in Android := "change-me",
libraryDependencies += "org.scalatest" %% "scalatest" % "1.6.1" % "test",
proguardOption in Android := """
-keepclassmembers class * implements java.io.Serializable {
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
"""
)

It can be useful to do so, as storing serializable objects in a Bundle is one of the more
straightforward ways of handling saveInstanceState/restoreInstanceState in an Activity.

rst commented May 18, 2012

FWIW, this can be worked around by adding the text suggested above to the
build settings in a project's build.scala. roughly like so:

lazy val fullAndroidSettings =
General.settings ++
AndroidProject.androidSettings ++
TypedResources.settings ++
AndroidMarketPublish.settings ++ Seq (
keyalias in Android := "change-me",
libraryDependencies += "org.scalatest" %% "scalatest" % "1.6.1" % "test",
proguardOption in Android := """
-keepclassmembers class * implements java.io.Serializable {
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
"""
)

It can be useful to do so, as storing serializable objects in a Bundle is one of the more
straightforward ways of handling saveInstanceState/restoreInstanceState in an Activity.

@rst

This comment has been minimized.

Show comment
Hide comment
@rst

rst May 18, 2012

Candidate fix submitted as pull request #131.

rst commented May 18, 2012

Candidate fix submitted as pull request #131.

@pimlott

This comment has been minimized.

Show comment
Hide comment
@pimlott

pimlott May 28, 2012

I agree about your use case (storing serializable objects in a Bundle), and this is exactly what I was trying to do. I did soon realize that since so many of the standard Scala classes are polymorphic, the lack of full type checking on deserialize (even with manifests as currently available) can bite. So now I usually use my own non-polymorphic classes instead.

That said, serialization and deserialization of standard Scala classes ought to work reliably. It took me a long time to figure out what was going wrong.

pimlott commented May 28, 2012

I agree about your use case (storing serializable objects in a Bundle), and this is exactly what I was trying to do. I did soon realize that since so many of the standard Scala classes are polymorphic, the lack of full type checking on deserialize (even with manifests as currently available) can bite. So now I usually use my own non-polymorphic classes instead.

That said, serialization and deserialization of standard Scala classes ought to work reliably. It took me a long time to figure out what was going wrong.

@ezh

This comment has been minimized.

Show comment
Hide comment
@ezh

ezh May 29, 2012

I tried to use serialization in my projects DigiControl/DigiSSHD, but there was an errors when I passed serialized object between different apk (transport level not significant) that shared in single library with serialized object.

I have something like client-server model that based on common code (DigiLib). Inside single apk all works well (intents and so on). So I am afraid that you find that your serialized data broken if you upgrade you application someday or try to send it to other application.

Of course ,I tried to set serial number by hand and I read proguard serialization manuals. So now I use only parcelable, even for persistent storage (Google prohibit this, but I read android source code and daresay, that parcelable chunk writen relatively well for my needs)

PS I think that scala bytecode generation maybe affected, so class in pure java will be consistent. But I don't want to use java code in my project.

ezh commented May 29, 2012

I tried to use serialization in my projects DigiControl/DigiSSHD, but there was an errors when I passed serialized object between different apk (transport level not significant) that shared in single library with serialized object.

I have something like client-server model that based on common code (DigiLib). Inside single apk all works well (intents and so on). So I am afraid that you find that your serialized data broken if you upgrade you application someday or try to send it to other application.

Of course ,I tried to set serial number by hand and I read proguard serialization manuals. So now I use only parcelable, even for persistent storage (Google prohibit this, but I read android source code and daresay, that parcelable chunk writen relatively well for my needs)

PS I think that scala bytecode generation maybe affected, so class in pure java will be consistent. But I don't want to use java code in my project.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment