Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rare nullpointer in Realm "setConstructionFinished" - Working as intended after clean & rebuild #4372

Closed
zoltish opened this issue Mar 23, 2017 · 37 comments

Comments

@zoltish
Copy link

commented Mar 23, 2017

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.

@non-binary

This comment has been minimized.

Copy link

commented Mar 23, 2017

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!

@Zhuinden

This comment has been minimized.

Copy link
Contributor

commented Mar 24, 2017

Interesting, maybe @zaki50 knows.

@zaki50

This comment has been minimized.

Copy link
Contributor

commented Mar 24, 2017

@zoltish Are you using Instant Run?

@zoltish

This comment has been minimized.

Copy link
Author

commented Mar 24, 2017

@zaki50 Nope, no instant run.

@zoltish

This comment has been minimized.

Copy link
Author

commented Mar 24, 2017

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.

@cmelchior cmelchior removed their assignment Mar 24, 2017

@cmelchior

This comment has been minimized.

Copy link
Contributor

commented Mar 24, 2017

@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?

@Zhuinden

This comment has been minimized.

Copy link
Contributor

commented Mar 24, 2017

What we can see from the stack trace is that this error occurred in a constructor while iterating a managed collection with an Iterator

@cmelchior

This comment has been minimized.

Copy link
Contributor

commented Mar 24, 2017

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: #3812

@zoltish

This comment has been minimized.

Copy link
Author

commented Mar 24, 2017

@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.

@cmelchior

This comment has been minimized.

Copy link
Contributor

commented Mar 24, 2017

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.

@zoltish

This comment has been minimized.

Copy link
Author

commented Mar 24, 2017

@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.

@cmelchior

This comment has been minimized.

Copy link
Contributor

commented Mar 24, 2017

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.

@zoltish

This comment has been minimized.

Copy link
Author

commented Mar 25, 2017

@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.

@zoltish

This comment has been minimized.

Copy link
Author

commented Mar 26, 2017

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!

@zoltish

This comment has been minimized.

Copy link
Author

commented Mar 27, 2017

Update: Happens on Gradle 2.2.0 as well :(

@nhachicha

This comment has been minimized.

Copy link
Contributor

commented Mar 27, 2017

@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
screen shot 2017-03-27 at 14 01 02

Note: you can change the Gradle logger level here

screen shot 2017-03-27 at 13 56 28

@zoltish

This comment has been minimized.

Copy link
Author

commented Apr 5, 2017

@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

@nhachicha

This comment has been minimized.

Copy link
Contributor

commented Apr 5, 2017

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.

@zaki50

This comment has been minimized.

Copy link
Contributor

commented Apr 5, 2017

@zoltish I guess all model classes are in a library project and you only applied Realm plugin to the library project. Is that true?

@zoltish

This comment has been minimized.

Copy link
Author

commented Apr 5, 2017

@zaki50 Theyre stored in an android library, but both the library and main android module have the realm plugin applied to them.

@zaki50

This comment has been minimized.

Copy link
Contributor

commented Apr 5, 2017

@zoltish In the library project, are you defining some modules which have library = true?

Something like:

@RealmModule(library = true, allClasses = true)
public class ZooAnimalsModule {
}
@zoltish

This comment has been minimized.

Copy link
Author

commented Apr 5, 2017

@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
}
@zaki50

This comment has been minimized.

Copy link
Contributor

commented Apr 5, 2017

I don't think any interfaces affect this issue.

@zaki50

This comment has been minimized.

Copy link
Contributor

commented Apr 14, 2017

Are you using Kotlin's incremental build?
Could you try to set kotlin.incremental=false in your grade.properties?

@Querschlag

This comment has been minimized.

Copy link

commented May 10, 2017

Same issue.
Realm 3.1.3, Kotlin project, Pixel as test device
Clean + Rebuild resolved it

@kneth

This comment has been minimized.

Copy link
Contributor

commented May 11, 2017

@zoltish Can you confirm that a clean and rebuild help?

@zoltish

This comment has been minimized.

Copy link
Author

commented May 11, 2017

@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.

@kneth

This comment has been minimized.

Copy link
Contributor

commented May 11, 2017

@zoltish Great to hear!

@kneth kneth closed this May 11, 2017

@akent

This comment has been minimized.

Copy link

commented May 12, 2017

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.

@zoltish

This comment has been minimized.

Copy link
Author

commented May 12, 2017

@akent Yes; however the issue seems to come up "randomly" and not at all correlating with changes to RealmObjects.

@akent

This comment has been minimized.

Copy link

commented May 12, 2017

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.

@akent

This comment has been minimized.

Copy link

commented May 12, 2017

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]
@akent

This comment has been minimized.

Copy link

commented May 15, 2017

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.

@itaispector

This comment has been minimized.

Copy link

commented Jun 12, 2018

@akent I don't want to be the party pooper, but I've included apply plugin: 'kotlin-kapt', and it still happens...

@Zhuinden

This comment has been minimized.

Copy link
Contributor

commented Jun 12, 2018

I've tried Realm with Kotlin and it worked just fine if Realm-android was applied after kotlin-kapt.

@itaispector

This comment has been minimized.

Copy link

commented Jun 12, 2018

@Zhuinden Indeed, I followed your answer on a different thread, cheers

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
You can’t perform that action at this time.