Realm-java: ReLinker NoClassDefFoundError exception

Created on 19 Jan 2016  路  16Comments  路  Source: realm/realm-java

Using 8.8.0-SNAPSHOT:

java.lang.NoClassDefFoundError: Failed resolution of: Lcom/getkeepsafe/relinker/ReLinker;
at io.realm.internal.RealmCore.loadLibrary(RealmCore.java:90)
at io.realm.RealmConfiguration$Builder.(RealmConfiguration.java:307)
at com.borg.forza.activities.Forza.setupRealm(Forza.java:75)
at com.borg.forza.activities.Forza.onCreate(Forza.java:63)
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1034)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4605)
at android.app.ActivityThread.access$1500(ActivityThread.java:148)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1353)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5312)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:901)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:696)
Caused by: java.lang.ClassNotFoundException: Didn't find class "com.getkeepsafe.relinker.ReLinker" on path: DexPathList[[zip file "/mnt/asec/com.borg.forza-1/base.apk"],nativeLibraryDirectories=[/mnt/asec/com.borg.forza-1/lib/arm, /vendor/lib, /system/lib]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
at io.realm.internal.RealmCore.loadLibrary(RealmCore.java:90)聽
at io.realm.RealmConfiguration$Builder.(RealmConfiguration.java:307)聽
at com.borg.forza.activities.Forza.setupRealm(Forza.java:75)聽
at com.borg.forza.activities.Forza.onCreate(Forza.java:63)聽
at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1034)聽`

T-Bug

All 16 comments

Are you using ProGuard by any chance?

Yes,
the rules taken from https://realm.io/docs/java/latest/#proguard:

-keep class io.realm.annotations.RealmModule
-keep @io.realm.annotations.RealmModule class *
-keep class io.realm.internal.Keep
-keep @io.realm.internal.Keep class * { _; }
-dontwarn javax._*
-dontwarn io.realm.**

Hi @roughboy
I was tried to run our example project with ProGuard enabled which seems to work fine: https://github.com/realm/realm-java/blob/master/examples/moduleExample/app/build.gradle

Note that if you use our new AAR distribution package as described here: https://github.com/realm/realm-java/blob/master/examples/moduleExample/app/build.gradle you don't need to provide your own ProGuard configuration.

Hi, seems like yours example is using AAR distribution while I got ReLinker error while using standard distribution method - compile 'io.realm:realm-android:0.88.0-SNAPSHOT'

As regarding AAR distribution - I checked it too. Unfortunately this time I get following error from gradle console during compilation:

    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:80)
    at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:61)
    ... 70 more
Error:java.lang.NoClassDefFoundError: com/squareup/javawriter/JavaWriter
    at io.realm.processor.RealmProxyClassGenerator.generate(RealmProxyClassGenerator.java:50)
    at io.realm.processor.RealmProcessor.process(RealmProcessor.java:145)
    at com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor(JavacProcessingEnvironment.java:794)
    at com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs(JavacProcessingEnvironment.java:705)
    at com.sun.tools.javac.processing.JavacProcessingEnvironment.access$1800(JavacProcessingEnvironment.java:91)
    at com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.run(JavacProcessingEnvironment.java:1035)
    at com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing(JavacProcessingEnvironment.java:1176)
    at com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1170)
    at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:856)
    at com.sun.tools.javac.main.Main.compile(Main.java:523)
    ... 91 more
Error:java.lang.ClassNotFoundException: com.squareup.javawriter.JavaWriter
    ... 101 more

I put sample project with repro here:
https://drive.google.com/file/d/0B_iAqFNIegRpVmZMVUhTRFBSckU/view?usp=sharing

Solution: add the Relinker dependency manually

compile 'io.realm:realm-android:0.88.0-SNAPSHOT'
compile 'com.github.KeepSafe:ReLinker:1.1'

With

#Relinker (for Realm 0.88.0+)
-keep class com.getkeepsafe.** { *; }
-keep class com.github.KeepSafe.** { *; }

The JAR will no longer be supported from 0.88 and onwards. As we use the new Transform API in order to support #2196, only the AAR and the Gradle plugin will be supported going forward.

...so in order to use ReLinker, I have to switch to the new and fairly experimental Gradle-plugin.

I guess I'll have to pray for the best at this point.

Depending on what you mean by experimental, we support back to 1.5.0 of the Google build tools.

I guess the question is, can I seamlessly upgrade from the JAR version to the AAR Gradle-Plugin without having to migrate, and will it be as stable on low-end devices and BlackBerry considering you guys are manipulating bytecode.

Yes, the upgrade from JAR to AAR does not require a migration of data. It is part of a larger release though which will have other breaking changes. You can see the current list in our changelog: https://github.com/realm/realm-java/blob/master/CHANGELOG.md

We are using standard tools and API's for manipulating the bytecode: Transform API and JavaAssist, plus the changes we make are actually a lot simpler than e.g. what Retrolambda and Instant Run do, so it should be safe.

Luckily, the only breaking change that affects me is having to switch to the Gradle plugin; otherwise my code is 0.84.0+ compatible (and with minor changes compatible back to 0.82.2) so the DynamicRealm doesn't affect me much.

The only interesting change is

BREAKING CHANGE: All thread local change listeners are now delayed 
    until the next Looper event instead of being triggered when committing.

Although I wasn't relying on that feature. Is there an issue for that somewhere? It essentially makes Realm objects not be up-to-date if you rely on saving data on the UI thread. I can see that cause trouble in basic examples.

It is part of a restructuring needed to support https://github.com/realm/realm-java/pull/2124

Oh. I can see why that's necessary, using for(int i = 0; i < list.size(); i++) { for reliable iteration behavior is not very intuitive, I've run into that problem many times when I first started using Realm.

Well, I'll update my app to the Gradle plugin then, and hope for the best.

Thanks for the info.

Wait, so how do I set up the AAR setup again?

Do I just need to use the Classpath dependency in the top-level build gradle

 classpath "io.realm:realm-gradle-plugin:${currentVersion}" //0.88.0-SNAPSHOT

and then in the app-level build gradle

apply plugin: 'realm-android'

But don't I need to still add a compile time dependency somewhere? Like,

compile 'io.realm:realm-android:0.88.0-SNAPSHOT'

Or is that no longer necessary with the new Gradle plugin? Maybe you have to set it as provided?

(I found this https://realm.io/news/android-installation-change/ so I guess the classpath and plugin are all that's needed...?)

@Zhuinden Yes, the only thing needed is the classpath and apply plugin. Our plugin will then automatically fetch all needed dependencies. You can see it working in our examples: https://github.com/realm/realm-java/blob/master/examples/introExample/build.gradle

If you are interested, you can see which dependencies we have here: https://github.com/realm/realm-java/blob/master/gradle-plugin/src/main/groovy/io/realm/gradle/Realm.groovy#L46-Lundefined , but it is done automatically.

Hi,

Same problem here, I have it working in one project without problems but I have this error in other where I am using realm inside a library.
Can I use realm gradle plugin inside an Android library?

Thanks!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

wyvern610 picture wyvern610  路  3Comments

Frasprite picture Frasprite  路  3Comments

jjorian picture jjorian  路  3Comments

mithrann picture mithrann  路  3Comments

Merlin1993 picture Merlin1993  路  3Comments