realm / realm-java

Realm is a mobile database: a replacement for SQLite & ORMs
http://realm.io
Apache License 2.0
11.45k stars 1.75k forks source link

'RealmProxy is not part of the schema' on 10.6.0+ in multi module projects #7650

Closed inri closed 2 years ago

inri commented 2 years ago

How frequently does the bug occur?

All the time

Description

When using a RealmModule from a library, since Realm version 10.6.0 (up until 10.10.1) doing copyToRealmOrUpdate() with a managed RealmObject crashes the App.

With Realm version v10.5.1 (or earlier) it works. Without the RealmModule it works.

We found out that prior 10.6.0 Realm did call DefaultRealmModuleMediator.hasPrimaryKeyImpl instead of CompositeMediator.hasPrimaryKeyImpl, despite the file DefaultRealmModuleMediator is also created in 10.6.0 upwards.

Stacktrace & log output

Caused by: io.realm.exceptions.RealmException: org_xyz_RealmObjectRealmProxy is not part of the schema for this Realm
        at io.realm.internal.modules.CompositeMediator.getMediator(CompositeMediator.java:205)
        at io.realm.internal.modules.CompositeMediator.hasPrimaryKeyImpl(CompositeMediator.java:111)
        at io.realm.internal.RealmProxyMediator.hasPrimaryKey(RealmProxyMediator.java:111)
        at io.realm.Realm.hasPrimaryKey(Realm.java:1836)
        at io.realm.Realm.checkHasPrimaryKey(Realm.java:1829)
        at io.realm.Realm.copyToRealmOrUpdate(Realm.java:1187)

Can you reproduce the bug?

Yes, always

Reproduction Steps

I can provide a minimal test project.

Here are the important parts. Simple RealmObject in app-module:

@RealmClass
open class Task : RealmObject() {
    @PrimaryKey
    var id: Long? = null

    var name: String? = null
}

Simple RealmObject in lib-module:

@RealmClass
open class LibTask: RealmObject() {
    var id: Long? = null
}

With RealmModule:

@RealmModule(library = true, allClasses = true) // same behavior with classes = [TestTask::class] instead
class RealmModuleFromLib

Application class:

class ModuleTestApp: Application() {

    override fun onCreate() {
        super.onCreate()
        Realm.init(this)

        val config = RealmConfiguration.Builder()
            .name("db")
            .allowQueriesOnUiThread(true)
            .allowWritesOnUiThread(true)
            .modules(Realm.getDefaultModule(), RealmModuleFromLib())
            .build()

        Realm.setDefaultConfiguration(config)

        RealmLog.setLevel(LogLevel.ALL)
    }
}

Insert this code anywhere:

Realm.getDefaultInstance().use { readRealm ->

            readRealm.executeTransaction { writeRealm ->
                Log.d("", "Create and insert new Task.")
                writeRealm.copyToRealmOrUpdate(Task().apply { this.id = 123L })
            }

            val task = readRealm.where<Task>().findFirst()
            Log.d("", "Retrieve managed Task (Id/Name): '${task?.id}/${task?.name}'")

            readRealm.executeTransaction { writeRealm ->
                Log.d("", "Edit Task and copyToRealmOrUpdate...")
                task?.name = "Test"
                writeRealm.copyToRealmOrUpdate(task)
            }

            Log.d("", "Show name of edited Task: '${task?.name}'")
        }

Version

10.6.0 upwards

What SDK flavour are you using?

Local Database only

Are you using encryption?

No, not using encryption

Platform OS and version(s)

Android minSDK 24, targetSDK 31

Build environment

Android Studio Bumblebee | 2021.1.1 Patch 2 Runtime version: 11.0.11+0-b60-7772763 aarch64, tried it also with 1.8 Android Build Tools version: 31.0.0 Android Gradle Tools: 7.1.2 Gradle version: 7.2

rorbech commented 2 years ago

Hi @inri. Thanks for the report. Will you be able to share your test project to speed up the investigations?

inri commented 2 years ago

@rorbech I replied to the mail and send it as zip file exported by AndroidStudio.

rorbech commented 2 years ago

@inri What mail? By any chance that you can just send it to claus.rorbech@mongodb.com?

o-nos commented 1 year ago

and what now? is there any solution? I'm also blocked by this issue when I need to have all of Realm-related config/classes/models to be in its lib-module.

bmunkholm commented 1 year ago

Could you please create a new issue with your details? Thanks!

o-nos commented 1 year ago

aha, I've just realized that my current Realm version is 6.1.1, so I will update to the latest 10.11.1 and will test now!

o-nos commented 1 year ago

the same even for 10.11.1 version of Realm. So will probably create an issue.

But it's really the same as Inri described here before: realm just swears that a class is not part of the schema for this Realm. after I moved the model class from :app module to a :sub-library module. Nothing has been changed except the model class's package. So I can't even build the app because Realm just can't recognize the same model.

rorbech commented 1 year ago

Hi @o-nos. The default schema only contains realm classes in the same module. If you want to use realm classes from an external module then you need to define a RealmModule in the external module and configure your realm to use the realm modules from the main app. You can see an example on how to do this in https://github.com/realm/realm-java/tree/master/examples/moduleExample.