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

Reading a Parcelable Object not work after creating serializer also! #169

Closed httyd98 closed 8 months ago

httyd98 commented 4 years ago

Paper version : 2.6 implementation 'io.paperdb:paperdb:2.6'

The error

2020-03-09 13:30:24.841 14867-14994/com.spel.substrack W/System.err: io.paperdb.PaperDbException: Couldn't read/deserialize file /data/user/0/com.spel.substrack/files/io.paperdb/abbonamenti.pt for table abbonamenti
2020-03-09 13:30:24.841 14867-14994/com.spel.substrack W/System.err:     at io.paperdb.DbStoragePlainFile.readTableFile(DbStoragePlainFile.java:298)
2020-03-09 13:30:24.841 14867-14994/com.spel.substrack W/System.err:     at io.paperdb.DbStoragePlainFile.select(DbStoragePlainFile.java:158)
2020-03-09 13:30:24.841 14867-14994/com.spel.substrack W/System.err:     at io.paperdb.Book.read(Book.java:73)
2020-03-09 13:30:24.841 14867-14994/com.spel.substrack W/System.err:     at com.spel.substrack.activities.MainActivity$onCreate$1.invoke(MainActivity.kt:69)
2020-03-09 13:30:24.841 14867-14994/com.spel.substrack W/System.err:     at com.spel.substrack.activities.MainActivity$onCreate$1.invoke(MainActivity.kt:26)
2020-03-09 13:30:24.841 14867-14994/com.spel.substrack W/System.err:     at org.jetbrains.anko.AsyncKt$doAsync$1.invoke(Async.kt:143)
2020-03-09 13:30:24.841 14867-14994/com.spel.substrack W/System.err:     at org.jetbrains.anko.AsyncKt$doAsync$1.invoke(Unknown Source:0)
2020-03-09 13:30:24.841 14867-14994/com.spel.substrack W/System.err:     at org.jetbrains.anko.AsyncKt$sam$java_util_concurrent_Callable$0.call(Unknown Source:2)
2020-03-09 13:30:24.841 14867-14994/com.spel.substrack W/System.err:     at java.util.concurrent.FutureTask.run(FutureTask.java:266)
2020-03-09 13:30:24.841 14867-14994/com.spel.substrack W/System.err:     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
2020-03-09 13:30:24.841 14867-14994/com.spel.substrack W/System.err:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
2020-03-09 13:30:24.841 14867-14994/com.spel.substrack W/System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
2020-03-09 13:30:24.841 14867-14994/com.spel.substrack W/System.err:     at java.lang.Thread.run(Thread.java:919)
2020-03-09 13:30:24.841 14867-14994/com.spel.substrack W/System.err: Caused by: com.esotericsoftware.kryo.KryoException: Buffer underflow.
2020-03-09 13:30:24.841 14867-14994/com.spel.substrack W/System.err: Serialization trace:
2020-03-09 13:30:24.841 14867-14994/com.spel.substrack W/System.err: mContent (io.paperdb.PaperTable)
2020-03-09 13:30:24.841 14867-14994/com.spel.substrack W/System.err:     at com.esotericsoftware.kryo.io.Input.require(Input.java:199)
2020-03-09 13:30:24.841 14867-14994/com.spel.substrack W/System.err:     at com.esotericsoftware.kryo.io.Input.readUtf8_slow(Input.java:560)
2020-03-09 13:30:24.842 14867-14994/com.spel.substrack W/System.err:     at com.esotericsoftware.kryo.io.Input.readUtf8(Input.java:553)
2020-03-09 13:30:24.842 14867-14994/com.spel.substrack W/System.err:     at com.esotericsoftware.kryo.io.Input.readString(Input.java:483)
2020-03-09 13:30:24.842 14867-14994/com.spel.substrack W/System.err:     at com.spel.substrack.dataStructures.SubSerial.read(Subscription.kt:117)
2020-03-09 13:30:24.842 14867-14994/com.spel.substrack W/System.err:     at com.spel.substrack.dataStructures.SubSerial.read(Subscription.kt:89)
2020-03-09 13:30:24.842 14867-14994/com.spel.substrack W/System.err:     at com.esotericsoftware.kryo.Kryo.readObject(Kryo.java:734)
2020-03-09 13:30:24.842 14867-14994/com.spel.substrack W/System.err:     at com.esotericsoftware.kryo.serializers.ObjectField.read(ObjectField.java:125)
2020-03-09 13:30:24.842 14867-14994/com.spel.substrack W/System.err:     at com.esotericsoftware.kryo.serializers.FieldSerializer.read(FieldSerializer.java:543)
2020-03-09 13:30:24.842 14867-14994/com.spel.substrack W/System.err:     at com.esotericsoftware.kryo.Kryo.readObject(Kryo.java:712)
2020-03-09 13:30:24.842 14867-14994/com.spel.substrack W/System.err:     at io.paperdb.DbStoragePlainFile.readContent(DbStoragePlainFile.java:307)
2020-03-09 13:30:24.842 14867-14994/com.spel.substrack W/System.err:     at io.paperdb.DbStoragePlainFile.readTableFile(DbStoragePlainFile.java:291)
2020-03-09 13:30:24.842 14867-14994/com.spel.substrack W/System.err:    ... 12 more
2020-03-09 13:30:24.842 14867-14994/com.spel.substrack E/ERRORE LETTURA: Couldn't read/deserialize file /data/user/0/com.spel.substrack/files/io.paperdb/abbonamenti.pt for table abbonamenti

The code

import android.app.Activity
import android.content.Context
import android.os.Parcel
import android.os.Parcelable
import com.esotericsoftware.kryo.DefaultSerializer
import com.esotericsoftware.kryo.Kryo
import com.esotericsoftware.kryo.Serializer
import com.esotericsoftware.kryo.io.Input
import com.esotericsoftware.kryo.io.Output
import com.spel.substrack.R
import com.spel.substrack.adapters.SubscriptionItem
import java.time.LocalDate

//classe per l'abbonamento
@DefaultSerializer(SubSerial::class)
data class Subscription(
    var ID: Int = -1,
    var nome: String = "",
    var costo: Float = 0.0f,
    var valuta: String = "",
    var listaPagamenti: MutableList<Pagamento> = mutableListOf(),
    var sincronizzato: Boolean = false,
    var periodicita: Periodicita = Periodicita.MENSILE,
    var moltiplicatore: Int = 1,
    var debitoAccumulato: Float = 0.0f,
    var debitoInStatistiche: Boolean = false,
    var debitoIncrementoRinnvo : Boolean = false,
    var note: String = "",
    var tags: List<TAGS> = listOf(),
    var colore: String = "",
    var linkLogo : String = ""): Parcelable {

    //costruttore per recuperare i dati dalla parcella
    constructor(parcel: Parcel) : this(
        ID = parcel.readInt(),
        nome = parcel.readString() ?: "",
        costo = parcel.readFloat(),
        valuta = parcel.readString() ?: "",
        listaPagamenti = parcel.readArray(ClassLoader.getSystemClassLoader())?.toMutableList() as MutableList<Pagamento>,
        sincronizzato = parcel.readByte() != 0.toByte(),
        periodicita = Periodicita.codeToPeriodicita(parcel.readInt()),
        moltiplicatore = parcel.readInt(),
        debitoAccumulato = parcel.readFloat(),
        debitoInStatistiche = parcel.readByte() != 0.toByte(),
        debitoIncrementoRinnvo = parcel.readByte() != 0.toByte(),
        note = parcel.readString() ?: "",
        tags = parcel.createIntArray()?.asList()?.map { TAGS.codeToTAG(it) } ?: emptyList<TAGS>(),
        colore = parcel.readString() ?: "",
        linkLogo = parcel.readString() ?: ""
    )

    //funzione per scrivere nella parcella
    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeInt(ID)
        parcel.writeString(nome)
        parcel.writeFloat(costo)
        parcel.writeString(valuta)
        parcel.writeParcelableArray(listaPagamenti.toTypedArray(),Parcelable.CONTENTS_FILE_DESCRIPTOR)
        parcel.writeByte(if (sincronizzato) 1 else 0)
        parcel.writeInt(periodicita.code)
        parcel.writeInt(moltiplicatore)
        parcel.writeFloat(debitoAccumulato)
        parcel.writeByte(if (debitoInStatistiche) 1 else 0)
        parcel.writeByte(if (debitoIncrementoRinnvo) 1 else 0)
        parcel.writeString(note)
        parcel.writeIntArray(tags.map { it.code }.toIntArray())
        parcel.writeString(colore)
        parcel.writeString(linkLogo)
    }

    //restituisco un hash per l'oggetto
    override fun describeContents() = hashCode()

    //creatore dell'oggetto parcellable
    companion object CREATOR : Parcelable.Creator<Subscription> {
        override fun createFromParcel(parcel: Parcel): Subscription {
            return Subscription(parcel)
        }
        override fun newArray(size: Int): Array<Subscription?> {
            return arrayOfNulls(size)
        }
    }
}

//serializzatore per subScription
class SubSerial : Serializer<Subscription>(){
    //riporto l'abbonametno in serializzato
    override fun write(kryo: Kryo?, output: Output?, sub: Subscription?) {
        if(kryo != null && output != null && sub != null){
            output.writeInt(sub.ID)
            output.writeString(sub.nome)
            output.writeFloat(sub.costo)
            output.writeString(sub.valuta)
            kryo.writeClassAndObject(output,sub.listaPagamenti)
            output.writeBoolean(sub.sincronizzato)
            output.writeInt(sub.periodicita.code)
            output.writeInt(sub.moltiplicatore)
            output.writeFloat(sub.debitoAccumulato)
            output.writeBoolean(sub.debitoInStatistiche)
            output.writeBoolean(sub.debitoIncrementoRinnvo)
            output.writeString(sub.note)
            kryo.writeObject(output,sub.tags.map { it.code })
            output.writeString(sub.colore)
            output.writeString(sub.linkLogo)
        }
    }
    //restituisco l'abbonamento dal serializzato
    override fun read(kryo: Kryo?, input: Input?, type: Class<Subscription>?): Subscription {
        return if(kryo != null && input != null && type != null){
            Subscription(
                ID = input.readInt(),
                nome = input.readString(),
                costo = input.readFloat(),
                valuta = input.readString(),
                listaPagamenti = kryo.readClassAndObject(input) as MutableList<Pagamento>,
                sincronizzato = input.readBoolean(),
                periodicita = Periodicita.codeToPeriodicita(input.readInt()),
                moltiplicatore = input.readInt(),
                debitoAccumulato = input.readFloat(),
                debitoInStatistiche = input.readBoolean(),
                debitoIncrementoRinnvo = input.readBoolean(),
                note = input.readString(),
                tags = (kryo.readClassAndObject(input) as List<Int>).map { TAGS.codeToTAG(it)},
                colore = input.readString(),
                linkLogo = input.readString()
            )
        }else{
            Subscription()
        }
    }
}

//classe per lo storico dei pagamenti
@DefaultSerializer(PagSerial::class)
data class Pagamento(
    var ID: Int = 0,
    var dataPagamento: LocalDate? = null,
    var costo: Float = 0.0f
): Parcelable{

    //costruttore per ricreare l'oggetto dalla parcella
    constructor(parcel: Parcel) : this(
        parcel.readInt(),
        LocalDate.ofEpochDay(parcel.readLong()),
        parcel.readFloat()
    )

    //scrvivo nella parcella
    override fun writeToParcel(dest: Parcel?, flags: Int) {
        if(dest != null) {
            dest.writeInt(ID)
            dataPagamento?.let {
                dest.writeLong(it.toEpochDay())
            }
            dest.writeFloat(costo)
        }
    }

    //restituisco un hash del contenuto
    override fun describeContents() = hashCode()

    //creatore dell'oggetto parcellable
    companion object CREATOR : Parcelable.Creator<Pagamento> {
        override fun createFromParcel(parcel: Parcel): Pagamento {
            return Pagamento(parcel)
        }
        override fun newArray(size: Int): Array<Pagamento?> {
            return arrayOfNulls(size)
        }
    }
}

//serializzatore per i pagamenti
class PagSerial : Serializer<Pagamento>(){
    //creazione da oggetto a dato serializzato
    override fun write(kryo: Kryo?, output: Output?, pag : Pagamento?) {
        if(kryo != null && output != null && pag != null){
            output.writeInt(pag.ID)
            pag.dataPagamento?.let {
                output.writeLong(it.toEpochDay())
            }
            output.writeFloat(pag.costo)
        }
    }
    //lettura dal dato serailizzato a pagamento
    override fun read(kryo: Kryo?, input: Input?, type: Class<Pagamento>?): Pagamento {
        return if(kryo != null && input != null && type != null) {
            Pagamento(input.readInt(), LocalDate.ofEpochDay(input.readLong()), input.readFloat())
        }else{
            Pagamento()
        }
    }
}

//enumeratore per la periodicità di pagamento
enum class Periodicita(val code: Int){
    MENSILE(R.string.rinnovo_mensile),
    ONE_TIME(R.string.rinnovo_onetime),
    GIORNALIERO(R.string.rinnovo_giornaliero),
    SETTIMANALE(R.string.rinnovo_settimanale),
    ANNUALE(R.string.rinnovo_annuale);

    //companion object dell'enumeratore
    companion object {
        //funzione che restituisce la periodicità da un codice
        fun codeToPeriodicita(code: Int): Periodicita {
            //restituisco la periodicità corrispondente
            return when (code) {
                MENSILE.code -> {
                    MENSILE
                }
                ONE_TIME.code -> {
                    ONE_TIME
                }
                GIORNALIERO.code -> {
                    GIORNALIERO
                }
                SETTIMANALE.code -> {
                    SETTIMANALE
                }
                ANNUALE.code -> {
                    ANNUALE
                }
                else -> {
                    MENSILE
                }
            }
        }
    }
}

//enumeratore per i tag
enum class TAGS(val code: Int) {
    CASA(R.string.tag_casa),
    MEDIA(R.string.tag_media),
    MUSICA(R.string.tag_musica),
    CINEMA(R.string.tag_cinema),
    SALUTE(R.string.tag_salute),
    SERVIZI(R.string.tag_servizi),
    GIOCHI(R.string.tag_giochi),
    TRASPORTI(R.string.tag_trasporti),
    TECNOLOGIA(R.string.tag_tecno),
    SPORT(R.string.tag_sport),
    INTRATTENIMENTO(R.string.tag_intratt),
    SHOPPING(R.string.tag_shopping),
    INTERNET(R.string.tag_internet);

    //companion object dell'enumeratore
    companion object {
        //funzione che restituisce il tag da un codice
        fun codeToTAG(code: Int): TAGS {
            //restituisco il tag corripspondente
            return when (code) {
                CASA.code ->{CASA}
                MEDIA.code ->{MEDIA}
                MUSICA.code ->{MUSICA}
                CINEMA.code ->{CINEMA}
                SALUTE.code ->{SALUTE}
                SERVIZI.code ->{SERVIZI}
                GIOCHI.code ->{GIOCHI}
                TRASPORTI.code ->{TRASPORTI}
                TECNOLOGIA.code ->{TECNOLOGIA}
                SPORT.code ->{SPORT}
                INTRATTENIMENTO.code ->{INTRATTENIMENTO}
                SHOPPING.code ->{SHOPPING}
                INTERNET.code ->{INTERNET}
                //restituisco il primo tag della lista
                else -> {CASA}
            }
        }
    }
}

The init of Paper in the onCreate

//inizializzo il database e aggiungo il serializzatore
        Paper.init(this)
        Paper.addSerializer(Subscription::class.java,SubSerial())
        Paper.addSerializer(Pagamento::class.java,PagSerial())

The reding of the list of Subscription

//inizilizzo il view pager
        viewPager = binding.mainViewPager
        //variabile per gli abbonamenti
        var abbonamenti: List<Subscription> = emptyList()
        //ricavo la lista degli abbonamenti
        doAsync {
            //ricavo la lista degli abbonamenti
            try {
                abbonamenti = Paper.book().read(
                    KEY_SUBSCRIPTION_BOOK,
                    emptyList<Subscription>()
                ).toList()

            }catch (ex: Exception){
                ex.printStackTrace()
                Log.e("ERRORE LETTURA", ex.message.toString())
            }
            //nel thread principale
            uiThread {
                //pulisco la lista di abbonamenti
                listaAbbonamenti.clear()
                //aggiungo glia bbonamenti ricavati alla lista
                listaAbbonamenti.addAll(abbonamenti)
                //imposto l'adapter per il view pager
                viewPager.adapter =
                    PagerAdapter(FRAG_NUMB, supportFragmentManager, listaAbbonamenti)

                //inizializzo i compas List<Subscription>onenti restanti del layout
                initLayout()
            }
        }

Anyone know how to solve the reading problem?

Can I use the serializer created with the Parcellable interface for reading and writing the database? Or does it have to be defined a separate serializer anyway?

pilgr commented 4 years ago

I can't see the code, how do you perform writing into Paper DB?