Closed zoltish closed 7 years ago
Hi @zoltish. Thanks for reaching out. I'm not experienced in this area so I can't say if it will be but we appreciate you filing either way (if it's difficult to find/fix or easy to). I'll have someone on the Java team look at this and see what we can do to get it fixed. Or at the very least leave it open until we can. Thanks again for filing!
Interesting, maybe @zaki50 knows.
@zoltish Are you using Instant Run
?
@zaki50 Nope, no instant run.
Just ran into it again, heres a longer stacktrace!
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void io.realm.ProxyState.setConstructionFinished()' on a null object reference
at io.realm.EquipmentRealmProxy.<init>(EquipmentRealmProxy.java:76)
at io.realm.DefaultRealmModuleMediator.newInstance(DefaultRealmModuleMediator.java:416)
at io.realm.BaseRealm.get(BaseRealm.java:488)
at io.realm.OrderedRealmCollectionImpl$RealmCollectionIterator.convertRowToObject(OrderedRealmCollectionImpl.java:525)
at io.realm.OrderedRealmCollectionImpl$RealmCollectionIterator.convertRowToObject(OrderedRealmCollectionImpl.java:518)
at io.realm.internal.Collection$Iterator.get(Collection.java:163)
at io.realm.internal.Collection$Iterator.next(Collection.java:130)
at core.data.transformer.Transformer$listTransformer$1.apply(Transformer.kt:37)
This is all part of an Observable<EquipmentModel>
and the crash happens in the next .map(transformer)
call. I can run the code infinite amount of times and it will always crash, and as mentioned it will simply go away once Ive rebuilt the project once or twice.
@zoltish It could be connected to how your initialize your Realm models, especially what kind of work you do in your constructors.
Can you post your entire Equipment
class?
What we can see from the stack trace is that this error occurred in a constructor while iterating a managed collection with an Iterator
Yes, but you can see it fails in a newInstance()
call, because it is trying to create a new proxy object. The initializers for the proxies are quite complex because they need to take into account multiple ways of setting "default" values in model classes.
Especially we still have this outstanding issue: https://github.com/realm/realm-java/pull/3812
@cmelchior They are pretty plain and boring.
open class Equipment : EquipmentModel, RealmObject() {
@PrimaryKey @EquipmentKey
var id: String? = null
var name: String? = null
override fun _getId(): String = id!!
override fun _getName(): String = name!!
}
The _methods
are simply "proxy" getters so that my pure java module can access the model fields.
Interesting. Have you seen it on anything but the Pixel? From your description I would say it sounds like a Instant Run bug, but if you say you don't use it 🤔 . If cleaning works it could also be some bug in the Google gradle plugin, but it is hard to tell.
@cmelchior Just for sanitys sake, I just checked and I am in fact, not using instant run 👍
I do most of my testing on a pixel, but Ill give another phone a go over the next couple of days just to see if it comes up on there too. Honestly I dont think it has much to do with the device itself though, but rather something with the annotation processing or something along those lines (or the gradle plugin, as you mention). The issue always goes away after a full clean, in which case all the generated code is recreated, and working again. Is the nullpointer above part of the code that gets generated? If so, I could also check the source when the issue comes up again to see if theres any difference in it after cleaning again.
Yes, it is coming from generated code. Our Bytecode transformer is injecting a call to realm$injectObjectContext()
into all constructors: https://github.com/realm/realm-java/blob/master/realm-transformer/src/main/groovy/io/realm/transformer/BytecodeModifier.groovy#L88
You can see it setting the proxyState reference here: https://github.com/realm/realm-java/blob/master/realm/realm-annotations-processor/src/test/resources/io/realm/AllTypesRealmProxy.java#L117
The error you are seeing, indicate that the bytecode transformer wasn't applied correctly for some reason.
@cmelchior Makes sense. The issue just came up again on a Nexus 6P, API 24 this morning. This time I did refactor a realm model class, after which Realm was looking for code that had changed (e.g. still referencing the old model class name and fields in a class thats no longer relevant) - I cant build the project at this point, so I clean it to delete and regen files, I have to do this a couple of times before it catches up and starts working again (ie above nullpointer stops being thrown).
Edit: Issue just came back in after "just" editing a layout xml file. Doesnt seem to matter what I change, as long as the project is being (re)compiled due to it. Seen it about 3-5 times in the past 2 hours now. Might try updating to the preview version of Android Studio (2.4) to see if its any better on there.
Jumping back down to gradle 2.2.0
from 2.3.0
seems to have fixed the issue. Will report back if I see it again!
Update: Happens on Gradle 2.2.0
as well :(
@zoltish just to make sure the the Bytecode transformer runs correctly, can you please, use Gradle with the --debug
option?
we have a couple logging messages inside the transformer, that you can see/filter via the Gradle Console
with the tag realm-logger
Note: you can change the Gradle logger level here
@nhachicha Sorry, didnt see your post til now! It seems to be running, however I can see two things that may be misbehaving:
1) [DEBUG] [realm-logger] Proxy Mediator Classes: []
I feel like this should have a value?
2) Perhaps this is intended, but it seems that processing of all Dagger classes (and other annotation processing tasks in the project) are labeled under the realm-logger.
Heres a gist of the whole thing:
https://gist.github.com/anonymous/672b53e7ee6c88de97b481fa20ee6229
Hi @zoltish thanks for the log,
I'm curious about EquipmentRealmProxy
being absent from the model
https://gist.github.com/anonymous/672b53e7ee6c88de97b481fa20ee6229#file-realm-L3228
Model Classes:
should list all the models defined in your app, the byte code transformer will then apply the different transformations to this model ex: add Realm accessor, and most importantly inject the object context, which is missing and causes the NPE in your case.
@zaki50 I think you're more familiar with this code path, could you pls have a look.
@zoltish I guess all model classes are in a library project and you only applied Realm plugin to the library project. Is that true?
@zaki50 Theyre stored in an android library, but both the library and main android module have the realm plugin applied to them.
@zoltish In the library project, are you defining some modules which have library = true
?
Something like:
@RealmModule(library = true, allClasses = true)
public class ZooAnimalsModule {
}
@zaki50 Nope, just plain models extending RealmObject() and implementing interfaces. I dont think the interfaces play any role in this? They just define the variables so that my pure java module can use the models independantly from Android.
open class Equipment : EquipmentModel, RealmObject() {
@PrimaryKey @EquipmentKey
override var id: String = EMPTY
@Required
override var name: String = EMPTY
}
interface EquipmentModel {
var id: String
var name: String
}
I don't think any interfaces affect this issue.
Are you using Kotlin's incremental build?
Could you try to set kotlin.incremental=false
in your grade.properties
?
Same issue. Realm 3.1.3, Kotlin project, Pixel as test device Clean + Rebuild resolved it
@zoltish Can you confirm that a clean and rebuild help?
@kneth Yup, that does the trick! Might be worth noting that I havent seen this issue in a good while now (hopefully me saying this wont jinx it). Besides a lot of new code, Ive upgraded Android Studio and the gradle plugin - which goes inline with the earlier suspicion about this all being a bug triggered by the gradle plugin.
@zoltish Great to hear!
To be clear, the problem is solved temporarily by a clean rebuild, but it comes right back again every time you change a RealmObject derived class.
Clean rebuild is not the solution; something is clearly stale and not being properly rebuilt automatically.
@akent Yes; however the issue seems to come up "randomly" and not at all correlating with changes to RealmObjects.
I can repro it every time with any change to the Chat.kt class in the demo repo linked in #4579. Let me turn on debug and see if I can diagnose further.
Debug gradle log from realm-demo project from a clean state: https://gist.githubusercontent.com/akent/b5f5e1b8bc52a6948cbb0b78ce1a4438/raw/63aac0e2ad2006e78726c5337a76a93ec89e51e2/build-from-clean.log
Debug gradle log after a minor change to Chat.kt: https://gist.githubusercontent.com/akent/e3cb5181223f5ce5d2a4194c7106cc6a/raw/39008c8c96f7ed3e94f15f1311e80b69cbbe1a30/build-after-change.log
Notable difference in the "after change" rebuild:
[DEBUG] [realm-logger] Proxy Mediator Classes: []
[DEBUG] [realm-logger] Model Classes: []
[DEBUG] [realm-logger] Managed Fields: []
vs clean:
[DEBUG] [realm-logger] Proxy Mediator Classes: [io.realm.DefaultRealmModuleMediator]
[DEBUG] [realm-logger] Realm: Marking as transformed DefaultRealmModuleMediator
[DEBUG] [realm-logger] Model Classes: [com.ghostflying.realmdemo.Chat]
[DEBUG] [realm-logger] Managed Fields: [chatId, chatTitle]
OK I did some more reading related to the problem and... drumroll
The answer (for me at least) is to include apply plugin: 'kotlin-kapt'
in the module level build.gradle.
I think this has been an issue since Kotlin 1.1.1 because incremental builds were enabled by default.
@akent I don't want to be the party pooper, but I've included apply plugin: 'kotlin-kapt'
, and it still happens...
I've tried Realm with Kotlin and it worked just fine if Realm-android
was applied after kotlin-kapt
.
@Zhuinden Indeed, I followed your answer on a different thread, cheers
I debated whether Id post this, but since it does come up once every 1-2 days I do think its important enough to at least mention. Hope my information can help you track it down, I appologize on beforehand for the slim data I can provide.
Setup: RxJava2 Dagger2 Kotlin
Crash log:
Attempt to invoke virtual method 'void io.realm.ProxyState.setConstructionFinished()' on a null object reference
Scenario: Usually when Im refactoring code that relates to how and what Dagger will provide. Ive never touched any of my Realm related code when this issue has come up.
Solution: Id do one clean & build, nothing. Restart Android Studio. Clean & build, and voila; it works.
Config: Android Studio 2.3 Realm 3.0.0 (Sync feature disabled) Kotlin 1.1.1 Dagger 2.1.0 RxJava 2.0.7 Tested on a Google Pixel, API 24
I dont really expect any miracle, seeings how rare it is and the slim data I can provide, but I hope it can provide some value to you in assisting with fixing it. Thanks for all your work, and let me know if theres anything else I can do to help with this.