pilgr / Paper

Paper is a fast NoSQL-like storage for Java/Kotlin objects on Android with automatic schema migration support.
Apache License 2.0
2.35k stars 234 forks source link

Couldn't deserialize file, caused by: java.lang.ClassNotFoundException #133

Closed shamilatesoglu closed 6 years ago

shamilatesoglu commented 6 years ago

It was fine until I updated my application. In my data class, I had to override equals() method, and added some transient fields, which I think shouldn't be the issue but I might be wrong. I am stuck with this for over three days and couldn't find any solution.

Here's my MainActivity's configurePaperDatabase method:

// Called in my initializeComponents method which called in onCreate method of MainActivity.
private void configurePaperDatabase() {
    Paper.init(mMainActivity);
    try {
        // retrieveOldData is a method which looks for older data 
        // before I migrated into PaperDB long ago.
        DataManager.read(retrieveOldData());
    } catch (Exception e) {
        Utilities.showBottomSheetErrorDialog(mMainActivity, e.getLocalizedMessage());
        e.printStackTrace();
    }
}

Here's my DataManager class's read method:

// Kayit is my data class.
public static void read(ArrayList<Kayit> oldData) {
    DataManager.kayitlar= Paper.book().read(Const.SAVE_FILE_NAME, oldData);
}

Here's my data class:

public class Kayit /* I have tried adding 'implements java.io.Serializable',
but it didn't change the outcome*/ {
    public String name;
    public float a;
    public float b;
    public float c;
    public float d;
    //    Goes on.
    //           .
    //           .
    // Here, I have changed some public float variables to public transient float variables,
    // but I thought that might be the case and 'undo'ed those changes. 
    // However, error didn't go away.

    // And I've added some new fields that don't need to be stored as 
    // they are handled by other methods of this class.
    public transient boolean e;
    public transient boolean f;
    public transient String g = "";
    public transient String h = "";

    public Kayit(String name){
        // some code that I didn't change...
    }

    // some other code that haven't changed by my update...
}

And here's the output:

07-28 19:38:37.080 22975-22975/? W/System.err: io.paperdb.PaperDbException: Couldn't 
read/deserialize file /data/user/0/package.my.app/files/io.paperdb/entries.pt for table entries
07-28 19:38:37.090 22975-22975/? W/System.err:     
        at io.paperdb.DbStoragePlainFile.readTableFile(Unknown Source)
        at io.paperdb.DbStoragePlainFile.select(Unknown Source)
        at io.paperdb.Book.read(Unknown Source)
        at package.my.app.data.c.a(Unknown Source)
        at package.my.app.activities.MainActivity.t(Unknown Source)
        at package.my.app.activities.MainActivity.r(Unknown Source)
        at package.my.app.activities.MainActivity.onCreate(Unknown Source)
        at android.app.Activity.performCreate(Activity.java:6904)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1136)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3266)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3415)
        at android.app.ActivityThread.access$1100(ActivityThread.java:229)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1821)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:148)
        at android.app.ActivityThread.main(ActivityThread.java:7325)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
    Caused by: com.esotericsoftware.kryo.KryoException: Unable to find class: package.my.app.a.c
    Serialization trace:
    mContent (io.paperdb.PaperTable)
07-28 19:38:37.090 22975-22975/? W/System.err:
        at com.esotericsoftware.kryo.util.DefaultClassResolver.readName(Unknown Source)
        at com.esotericsoftware.kryo.util.DefaultClassResolver.readClass(Unknown Source)
        at com.esotericsoftware.kryo.Kryo.readClass(Unknown Source)
        at com.esotericsoftware.kryo.Kryo.readClassAndObject(Unknown Source)
        at com.esotericsoftware.kryo.serializers.CollectionSerializer.read(Unknown Source)
        at com.esotericsoftware.kryo.serializers.CollectionSerializer.read(Unknown Source)
        at com.esotericsoftware.kryo.Kryo.readObject(Unknown Source)
        at com.esotericsoftware.kryo.serializers.ObjectField.read(Unknown Source)
        at com.esotericsoftware.kryo.serializers.FieldSerializer.read(Unknown Source)
        at com.esotericsoftware.kryo.Kryo.readObject(Unknown Source)
        at io.paperdb.DbStoragePlainFile.readContent(Unknown Source)
        ... 19 more
    Caused by: java.lang.ClassNotFoundException: package.my.app.a.c
        at java.lang.Class.classForName(Native Method)
        at java.lang.Class.forName(Class.java:324)
        ... 30 more
    Caused by: java.lang.ClassNotFoundException: Didn't find class "package.my.app.a.c" on path: 
DexPathList[[zip file "/data/app/package.my.app-2/base.apk"],
nativeLibraryDirectories=[/data/app/package.my.app-2/lib/arm, /vendor/lib, /system/lib]]
07-28 19:38:37.090 22975-22975/? W/System.err:     
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
        ... 32 more
        Suppressed: java.lang.ClassNotFoundException: package.my.app.a.c
        at java.lang.Class.classForName(Native Method)
        at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
        at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
            ... 33 more
        Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; 
no stack trace available

I also use Proguard and added -keep class package.my.app.data.Kayit in proguard-rules.pro after I came upon the error, but that didn't make the error go away too. Also, I had to enable multidex as my app got bigger with some of Google's services. I couldn't find any solution. And I don't know if this is the right place but, I really need help.

shamilatesoglu commented 6 years ago

By disabling multidex and deleting -keep class package.my.app.data.Kayit from proguard-rules.pro, I was able to make the error go away but this time it falsely reads data. What could be the reason behind this?

pilgr commented 6 years ago

According to the error message Didn't find class "package.my.app.a.c" here is what happened:

  1. You have saved the data with Proguard enabled, meaning data has been saved for the class my.app.a.c and not for the my.app.data.Kayit.
  2. Then you've tried to read the data but with the additional Proguard rule preventing changing class name for Kayit. And at this moment PaperDb has thrown an exception because of the class my.app.a.c no longer exist in the new build.

The solutions:

  1. If you need to recover saved data: copy the Kayit class at the exact same location with the same name as expected - my.app.a.c and try to reread data and save under proper class name.
  2. If you don't need that data anymore - you can remove the previous data file (or save new data under another key) and use the app as is.
shamilatesoglu commented 6 years ago

I have tried to read the data with the additional Proguard rule after the error showed up. But I got the idea thanks to you :D. I did the first solution you provided, the error don't show up but this time it falsely reads the data, like it got corrupted or something. What could be the reason behind this? Thank you very much anyways. I should have included my data class in proguard file in the first place.