Realm-java: OkBuck support

Created on 1 Jan 2017  路  39Comments  路  Source: realm/realm-java

Goal

Build my app that uses Realm with OkBuck.

Expected Results

Build and runs normally as if I had built with Gradle.

Actual Results

The build and APK are successfully generated, but when I run the app an error is raised, forcing close the app. If I build the same dependencies with Gradle, not using OkBuck, it runs perfectly. Logcat:

E/AndroidRuntime( 3447): FATAL EXCEPTION: main
E/AndroidRuntime( 3447): Process: mobile.nonaka.com.nonakaapp.ci, PID: 3447
E/AndroidRuntime( 3447): java.lang.ExceptionInInitializerError: RealmTransformer doesn't seem to be applied. Please update the project configuration to use the Realm Gradle plugin. See https://realm.io/news/android-installation-change/
E/AndroidRuntime( 3447):    at io.realm.RealmConfiguration.<clinit>(RealmConfiguration.java:77)
E/AndroidRuntime( 3447):    at io.realm.RealmConfiguration$Builder.initializeBuilder(RealmConfiguration.java:428)
E/AndroidRuntime( 3447):    at io.realm.RealmConfiguration$Builder.<init>(RealmConfiguration.java:391)
E/AndroidRuntime( 3447):    at mobile.nonaka.com.nonakaapp.NONAKAApplication.onCreate(NONAKAApplication.java:44)
E/AndroidRuntime( 3447):    at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1007)
E/AndroidRuntime( 3447):    at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4344)
E/AndroidRuntime( 3447):    at android.app.ActivityThread.access$1500(ActivityThread.java:135)
E/AndroidRuntime( 3447):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
E/AndroidRuntime( 3447):    at android.os.Handler.dispatchMessage(Handler.java:102)
E/AndroidRuntime( 3447):    at android.os.Looper.loop(Looper.java:136)
E/AndroidRuntime( 3447):    at android.app.ActivityThread.main(ActivityThread.java:5017)
E/AndroidRuntime( 3447):    at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime( 3447):    at java.lang.reflect.Method.invoke(Method.java:515)
E/AndroidRuntime( 3447):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
E/AndroidRuntime( 3447):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
E/AndroidRuntime( 3447):    at dalvik.system.NativeStart.main(Native Method)

https://realm.io/news/android-installation-change did not help.

Steps & Code to Reproduce

Build any app with Realm with OkBuck and run it.

Code Sample

NONAKAApplication.java line 44 has this code:

            RealmConfiguration realmConfiguration = new RealmConfiguration.Builder(this)
                    .schemaVersion(1)
                    .encryptionKey(realmKeyProvider.getRealmKey())
                    .deleteRealmIfMigrationNeeded()
                    .build();

This is my Gradle configuration that I used to generate the Buck files:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath "io.realm:realm-gradle-plugin:2.2.1"
    }
}

apply plugin: 'realm-android'

Version of Realm and tooling

Realm version(s): 2.2.1

Realm sync feature enabled: no

Android Studio version: 2.2.3

Which Android version and device: Any device
minSdkVersion 18
targetSdkVersion 25
compileSdkVersion 25
buildToolsVersion '25.0.2'

OkBuck: 0.13.1

Gradle: 3.2

Android Gradle Plugin: 2.2.3

Thanks a lot.

O-Community T-Feature

Most helpful comment

okbuck takes care of passing in the android bootclasspath as a java system property.

The syncEnabled setting can be in the config file.

Okbuck transform CLI can create a transform in two ways.

  • A class name with an empty constructor
  • A class name with a java.io.File argument constructor

The file can contain anything in it. In Realm's case it can be a simple config file like

realm.config

realm.syncEnabled=true

The transform can then read the file and parse it in whichever format it wants it in.

All 39 comments

That's because OkBuck doesn't support the Transform API yet.

image

@Zhuinden didn't notice that. Thanks a lot! Does anyone know though if it is possible to use Realm without this Transform API (maybe a older version of Realm)?

The last Realm that does not use the Realm-Transformer and the Transform API is compile "io.realm:realm-android:0.87.5"

In that version of Realm, RealmObjects cannot have custom methods, and custom logic in getters/setters.

Also, RealmResults are live in transactions, so you need to reverse iterate them instead of using for(Blah blah: blahs).

@Zhuinden thanks man. It helped me a lot!

Transform api support is actually available in okbuck, but it is not documented yet. It's a bit of work to setup right now, so we are working to make it more plug and play and will document it fully at that point.

Thanks for the info @kageiit 馃憤

Just for future reference:
https://github.com/uber/okbuck/issues/305

Question for Realm maintainers. The way transforms work in buck is that they do not have access to the gradle project model as they are run like commandline applications. This would require the RealTransformer to provide an alternate constructor that can accept a config file as an input for various configuration options instead of relying on the gradle plugin extension. Would like your thoughts on the matter

Given the above, and that support for Transformers have been merged in OkBuck I'm re-opening this as a feature request for adding support for OkBuck. We would have to look more closely at how specifically the config file looks like, but just browsing our RealmTransformer we only use two things from the Gradle project:

1) We have a custom realm closure with a setting syncEnabled. I don't know how OkBuck handles custom configuration closures, but we would have to migrate that anyway.

2) We access project.android.bootClasspath to acquire a reference to the android.jar. This would have to be provided by Buck somehow I think.

@zaki50 Do you have any input to this?

okbuck takes care of passing in the android bootclasspath as a java system property.

The syncEnabled setting can be in the config file.

Okbuck transform CLI can create a transform in two ways.

  • A class name with an empty constructor
  • A class name with a java.io.File argument constructor

The file can contain anything in it. In Realm's case it can be a simple config file like

realm.config

realm.syncEnabled=true

The transform can then read the file and parse it in whichever format it wants it in.

I also noticed that the extension is the only reason the transform relies on the gradle api. If it were possible to specify the configuration through a simple file, that dependency can be completely removed and the transform can be a 100% pure java project then. The configuration file can be created on the fly by the plugin and passed to the registerTransform() call without breaking existing users.

@cmelchior I feel supporting OkBuck is not so difficult, I'm not familiar with it.

I'll spend a bit of my time more to investigate OkBuck.

I wrote another transformer (RealmTransformerOkBuck) whose constructor accepted a File parameter.

I didn't test it at all, but is it what you mean?

// diff was removed

I would assume we could re-use the same transformer class and just keep the differences in the constructors? In our case it is just two variables, so should be doable?

@cmelchior Ah, yes.

I've updated the diff

diff --git a/gradle-plugin/src/main/groovy/io/realm/gradle/Realm.groovy b/gradle-plugin/src/main/groovy/io/realm/gradle/Realm.groovy
index 43bf3f89c..bf932bf30 100644
--- a/gradle-plugin/src/main/groovy/io/realm/gradle/Realm.groovy
+++ b/gradle-plugin/src/main/groovy/io/realm/gradle/Realm.groovy
@@ -54,7 +54,13 @@ class Realm implements Plugin<Project> {
             usesAptPlugin = true
         }

-        project.android.registerTransform(new RealmTransformer(project))
+        def syncEnabled = project?.realm?.syncEnabled != null && project.realm.syncEnabled
+        def bootClassPathList = new ArrayList<String>()
+        project.android.bootClasspath.each {
+            bootClassPathList.add(it.absolutePath)
+        }
+
+        project.android.registerTransform(new RealmTransformer(syncEnabled, bootClassPathList))

         project.repositories.add(project.getRepositories().jcenter())
         project.dependencies.add("compile", "io.realm:realm-annotations:${Version.VERSION}")
diff --git a/realm-transformer/src/main/groovy/io/realm/transformer/RealmTransformer.groovy b/realm-transformer/src/main/groovy/io/realm/transformer/RealmTransformer.groovy
index e6e481355..cf03de5d6 100644
--- a/realm-transformer/src/main/groovy/io/realm/transformer/RealmTransformer.groovy
+++ b/realm-transformer/src/main/groovy/io/realm/transformer/RealmTransformer.groovy
@@ -26,8 +26,6 @@ import io.realm.annotations.Ignore
 import io.realm.annotations.RealmClass
 import javassist.ClassPool
 import javassist.CtClass
-import javassist.LoaderClassPath
-import org.gradle.api.Project
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory

@@ -44,12 +42,36 @@ import static com.android.build.api.transform.QualifiedContent.*
 class RealmTransformer extends Transform {

     private Logger logger = LoggerFactory.getLogger('realm-logger')
-    private Project project
+    private boolean syncEnabled;
+    private List<String> bootClassPathList;

-    public RealmTransformer(Project project) {
-        this.project = project
+    public RealmTransformer(boolean syncEnabled, List<String> bootClassPathList) {
+        this.syncEnabled = syncEnabled
+        this.bootClassPathList = bootClassPathList
     }

+    // constructor for OkBuck
+    public RealmTransformer(File configFile) {
+        if (!propertiesFile.exists()) {
+            throw new FileNotFoundException(configFile.absolutePath)
+        }
+        Properties properties = new Properties()
+        configFile.withInputStream {
+            properties.load(it)
+        }
+        syncEnabled = Boolean.valueOf(properties.getProperty("realm.syncEnabled", "false"))
+        def bootClassPath = properties.getProperty("realm.bootClassPath")
+        if (bootClassPath == null || bootClassPath.empty) {
+            throw new Exception("realm.bootClassPath is not set in the configuration file.")
+        }
+
+        bootClassPathList = new ArrayList<>()
+        bootClassPath.split(',').each {
+            bootClassPathList.add(it.trim())
+        }
+    }
+
+
     @Override
     String getName() {
         return "RealmTransformer"
@@ -177,8 +199,7 @@ class RealmTransformer extends Transform {
         def env = System.getenv()
         def disableAnalytics = env["REALM_DISABLE_ANALYTICS"]
         if (disableAnalytics == null || disableAnalytics != "true") {
-            boolean sync = project?.realm?.syncEnabled != null && project.realm.syncEnabled
-            def analytics = new RealmAnalytics(packages as Set, containsKotlin, sync)
+            def analytics = new RealmAnalytics(packages as Set, containsKotlin, this.syncEnabled)
             analytics.execute()
         }
     }
@@ -291,8 +312,8 @@ class RealmTransformer extends Transform {
     // See https://code.google.com/p/android/issues/detail?id=209426
     private void addBootClassesToClassPool(ClassPool classPool) {
         try {
-            project.android.bootClasspath.each {
-                String path = it.absolutePath
+            this.bootClassPathList.each {
+                String path = it
                 logger.debug "Add boot class " + path + " to class pool."
                 classPool.appendClassPath(path)
             }
diff --git a/realm/realm-library/build.gradle b/realm/realm-library/build.gradle
index ac7f1affb..94f4be798 100644
--- a/realm/realm-library/build.gradle
+++ b/realm/realm-library/build.gradle
@@ -117,7 +117,12 @@ coveralls.jacocoReportPath = "${buildDir}/reports/coverage/debug/report.xml"

 import io.realm.transformer.RealmTransformer

-android.registerTransform(new RealmTransformer())
+def syncEnabled = false
+def bootClassPathList = new ArrayList<String>()
+project.android.bootClasspath.each {
+    bootClassPathList.add(it.absolutePath)
+}
+android.registerTransform(new RealmTransformer(syncEnabled, bootClassPathList))

 repositories {
     maven { url "https://jitpack.io" }

@kageiit How can I test transformer-enabled OkBuck?
And currently I wrote a code to get boot class path from the configuration file.
Which system property should we use for bootclasspath?

@zaki50 the android bootclasspath is already passed in the transform invocation as a referenced input jar.

To test it just add to your root build.gradle:

okBuck {
...
    experimental {
        transform = true
    }

    transform {
        transforms = [
                'APP-FLAVOUR'     : [
                        [transform : "FULL_QUALIFIED_CLASS_NAME",
                         configFile: "CONFIG_FILE_PATH"]
                ],
        ]
    }
}

dependencies {
    transform REALM_DEPENDENCY
}

I also just cut and released v0.17.0 of okbuck that has support for the transforms baked in. You can use the configuration snippet @malbano posted above to test it out.

More details in the release notes: https://github.com/uber/okbuck/releases/tag/v0.17.0

@kageiit @malbano Thanks. I'll test my code and make a PR for this.

I've got some errors.

+ java -Dokbuck.inJarsDir=/Users/zaki/fromgit/realm/realm_template/buck-out/bin/app/java_classes_preprocess_in_bin_debug -Dokbuck.outJarsDir=/Users/zaki/fromgit/realm/realm_template/buck-out/bin/app/java_classes_preprocess_out_bin_debug -Dokbuck.androidBootClasspath=/usr/local/Cellar/android-sdk/24.4.1_1/platforms/android-24/android.jar:/usr/local/Cellar/android-sdk/24.4.1_1/platforms/android-24/optional/org.apache.http.legacy.jar -Dokbuck.configFile=/Users/zaki/fromgit/realm/realm_template/buck-out/gen/.okbuck/cache/transform/realm.config -Dokbuck.transformClass=io.realm.transformer.RealmTransformer -cp /Users/zaki/fromgit/realm/realm_template/buck-out/gen/.okbuck/cache/transform/okbuck_transform.jar com.uber.okbuck.transform.CliTransform
Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8 -Dgroovy.source.encoding=UTF-8
java.io.IOException: Stream closed
    at java.io.BufferedInputStream.getInIfOpen(BufferedInputStream.java:159)
    at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
    at java.io.BufferedInputStream.read(BufferedInputStream.java:265)
    at java.io.DataInputStream.readUnsignedShort(DataInputStream.java:337)
    at java.io.DataInputStream.readUTF(DataInputStream.java:589)
    at java.io.DataInputStream.readUTF(DataInputStream.java:564)
    at org.codehaus.groovy.reflection.GeneratedMetaMethod$DgmMethodRecord.loadDgmInfo(GeneratedMetaMethod.java:177)
    at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.registerMethods(MetaClassRegistryImpl.java:186)
    at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.<init>(MetaClassRegistryImpl.java:96)
    at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.<init>(MetaClassRegistryImpl.java:74)
    at groovy.lang.GroovySystem.<clinit>(GroovySystem.java:36)
    at org.codehaus.groovy.runtime.InvokerHelper.<clinit>(InvokerHelper.java:65)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.createCallStaticSite(CallSiteArray.java:75)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.createCallSite(CallSiteArray.java:162)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
    at io.realm.transformer.RealmTransformer.<init>(RealmTransformer.groovy:44)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at com.uber.okbuck.transform.TransformRunner.runTransform(TransformRunner.java:74)
    at com.uber.okbuck.transform.CliTransform.main(CliTransform.java:96)
    at com.uber.okbuck.transform.CliTransform.main(CliTransform.java:51)
Exception in thread "main" java.lang.RuntimeException: groovy.lang.MissingMethodException: No signature of method: java.util.LinkedList.each() is applicable for argument types: (io.realm.transformer.RealmTransformer$_getClassNames_closure16) values: [io.realm.transformer.RealmTransformer$_getClassNames_closure16@2a17b7b6]
Possible solutions: wait(), wait(long), add(java.lang.Object), add(java.lang.Object), add(java.lang.Object), push(java.lang.Object)
    at com.uber.okbuck.transform.CliTransform.main(CliTransform.java:98)
    at com.uber.okbuck.transform.CliTransform.main(CliTransform.java:51)
Caused by: groovy.lang.MissingMethodException: No signature of method: java.util.LinkedList.each() is applicable for argument types: (io.realm.transformer.RealmTransformer$_getClassNames_closure16) values: [io.realm.transformer.RealmTransformer$_getClassNames_closure16@2a17b7b6]
Possible solutions: wait(), wait(long), add(java.lang.Object), add(java.lang.Object), add(java.lang.Object), push(java.lang.Object)
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:58)
    at org.codehaus.groovy.runtime.callsite.PojoMetaClassSite.call(PojoMetaClassSite.java:49)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
    at io.realm.transformer.RealmTransformer.getClassNames(RealmTransformer.groovy:247)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
    at org.codehaus.groovy.runtime.callsite.StaticMetaMethodSite$StaticMetaMethodSiteNoUnwrapNoCoerce.invoke(StaticMetaMethodSite.java:151)
    at org.codehaus.groovy.runtime.callsite.StaticMetaMethodSite.callStatic(StaticMetaMethodSite.java:102)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallStatic(CallSiteArray.java:56)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:194)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:206)
    at io.realm.transformer.RealmTransformer.transform(RealmTransformer.groovy:110)
    at com.android.build.api.transform.Transform.transform(Transform.java:308)
    at com.uber.okbuck.transform.TransformRunner.runTransform(TransformRunner.java:104)
    at com.uber.okbuck.transform.TransformRunner.runTransform(TransformRunner.java:80)
    at com.uber.okbuck.transform.CliTransform.main(CliTransform.java:96)
    ... 1 more

BUILD FAILED: //app:bin_debug failed with exit code 1:
genrule
stderr: + java -Dokbuck.inJarsDir=/Users/zaki/fromgit/realm/realm_template/buck-out/bin/app/java_classes_preprocess_in_bin_debug -Dokbuck.outJarsDir=/Users/zaki/fromgit/realm/realm_template/buck-out/bin/app/java_classes_preprocess_out_bin_debug -Dokbuck.androidBootClasspath=/usr/local/Cellar/android-sdk/24.4.1_1/platforms/android-24/android.jar:/usr/local/Cellar/android-sdk/24.4.1_1/platforms/android-24/optional/org.apache.http.legacy.jar -Dokbuck.configFile=/Users/zaki/fromgit/realm/realm_template/buck-out/gen/.okbuck/cache/transform/realm.config -Dokbuck.transformClass=io.realm.transformer.RealmTransformer -cp /Users/zaki/fromgit/realm/realm_template/buck-out/gen/.okbuck/cache/transform/okbuck_transform.jar com.uber.okbuck.transform.CliTransform
Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8 -Dgroovy.source.encoding=UTF-8
java.io.IOException: Stream closed
    at java.io.BufferedInputStream.getInIfOpen(BufferedInputStream.java:159)
    at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
    at java.io.BufferedInputStream.read(BufferedInputStream.java:265)
    at java.io.DataInputStream.readUnsignedShort(DataInputStream.java:337)
    at java.io.DataInputStream.readUTF(DataInputStream.java:589)
    at java.io.DataInputStream.readUTF(DataInputStream.java:564)
    at org.codehaus.groovy.reflection.GeneratedMetaMethod$DgmMethodRecord.loadDgmInfo(GeneratedMetaMethod.java:177)
    at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.registerMethods(MetaClassRegistryImpl.java:186)
    at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.<init>(MetaClassRegistryImpl.java:96)
    at org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.<init>(MetaClassRegistryImpl.java:74)
    at groovy.lang.GroovySystem.<clinit>(GroovySystem.java:36)
    at org.codehaus.groovy.runtime.InvokerHelper.<clinit>(InvokerHelper.java:65)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.createCallStaticSite(CallSiteArray.java:75)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.createCallSite(CallSiteArray.java:162)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
    at io.realm.transformer.RealmTransformer.<init>(RealmTransformer.groovy:44)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at com.uber.okbuck.transform.TransformRunner.runTransform(TransformRunner.java:74)
    at com.uber.okbuck.transform.CliTransform.main(CliTransform.java:96)
    at com.uber.okbuck.transform.CliTransform.main(CliTransform.java:51)
Exception in thread "main" java.lang.RuntimeException: groovy.lang.MissingMethodException: No signature of method: java.util.LinkedList.each() is applicable for argument types: (io.realm.transformer.RealmTransformer$_getClassNames_closure16) values: [io.realm.transformer.RealmTransformer$_getClassNames_closure16@2a17b7b6]
Possible solutions: wait(), wait(long), add(java.lang.Object), add(java.lang.Object), add(java.lang.Object), push(java.lang.Object)
    at com.uber.okbuck.transform.CliTransform.main(CliTransform.java:98)
    at com.uber.okbuck.transform.CliTransform.main(CliTransform.java:51)
Caused by: groovy.lang.MissingMethodException: No signature of method: java.util.LinkedList.each() is applicable for argument types: (io.realm.transformer.RealmTransformer$_getClassNames_closure16) values: [io.realm.transformer.RealmTransformer$_getClassNames_closure16@2a17b7b6]
Possible solutions: wait(), wait(long), add(java.lang.Object), add(java.lang.Object), add(java.lang.Object), push(java.lang.Object)
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:58)
    at org.codehaus.groovy.runtime.callsite.PojoMetaClassSite.call(PojoMetaClassSite.java:49)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
    at io.realm.transformer.RealmTransformer.getClassNames(RealmTransformer.groovy:247)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
    at org.codehaus.groovy.runtime.callsite.StaticMetaMethodSite$StaticMetaMethodSiteNoUnwrapNoCoerce.invoke(StaticMetaMethodSite.java:151)
    at org.codehaus.groovy.runtime.callsite.StaticMetaMethodSite.callStatic(StaticMetaMethodSite.java:102)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallStatic(CallSiteArray.java:56)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:194)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:206)
    at io.realm.transformer.RealmTransformer.transform(RealmTransformer.groovy:110)
    at com.android.build.api.transform.Transform.transform(Transform.java:308)
    at com.uber.okbuck.transform.TransformRunner.runTransform(TransformRunner.java:104)
    at com.uber.okbuck.transform.TransformRunner.runTransform(TransformRunner.java:80)
    at com.uber.okbuck.transform.CliTransform.main(CliTransform.java:96)
    ... 1 more

One is java.io.IOException: Stream closed at the line private Logger logger = LoggerFactory.getLogger('realm-logger') in RealmTransformer.groovy

Another is groovy.lang.MissingMethodException: No signature of method: java.util.LinkedList.each() at https://github.com/realm/realm-java/blob/v2.3.0/realm-transformer/src/main/groovy/io/realm/transformer/RealmTransformer.groovy#L227
We are expecting groovy's list, but actual instance from CliTransform seems an instance of java.util.LinkedList.

@kageiit What do you think? Can you fix it in OkBuck?

@zaki50 It's easier to review if you just push a Pull Request and mark it as "In Progress" 馃槃

@zaki50 I think the problem lies here: https://github.com/realm/realm-java/blob/master/realm-transformer/build.gradle#L50

the gradleApi() and localGroovy() declarations basically do not get packaged into the pom of the transform becuase they are expected to be provided by the upstream project's gradle installation

so when you do

dependencies {
  transform 'realm-transform'
}

Okbuck will pull in real-transform and its pom dependencies to make a fat jar that can be run via the transform-cli in buck. Since buck itself does not have a groovy installation, that needs to be packaged into the fat jar as well, so there are a couple of options

  • Add groovy and gradle as transform dependencies as well
dependencies {
  transform 'real-transform'
  transform localGroovy()
  transform gradleApi()
}
  • Make the realm-transformer a pure java project and remove dependencies on groovy and gradle api completely. I think with #4133 the gradleAPi() dpenednecy is no longer required as you have a provider interface. You really only need the groovy dependency

Thanks @kageiit
I tried the first option last week but no success (IIRC). I'll confirm that later.
I'd like to avoid the second option. We are using groovy methods in many places...

I think import groovy.io.FileType is the only actual groovy-specific thing.

I'm sure this could be rewritten to Java without too much trouble.

Hmm...

Do you think adding the incremental support could have also solved this one?

There is only one groovy file left - https://github.com/realm/realm-java/blob/539054e7923f7efda693733344a5cf436d377b0e/realm-transformer/src/main/groovy/io/realm/transformer/GroovyUtil.groovy

If this is moved over, then there is no reliance on groovy types and it could enable okbuck support

I'm getting the same error with the following okbuck configuration:

okBuck {
...
    experimental {
        transform = true
    }
    transform {
        transforms = [
                'debug'     : [
                        [transform : "io.realm.transformer.RealmTransformer",
                ],
        ]
    }
}
dependencies {
    transform "io.realm:realm-gradle-plugin:5.3.1"
}

Is there something I'm missing?

@jtrouvere you need to try with 5.4.0-SNAPSHOT

And you also need to run it for release if that's a thing

I still get the error even though i use 5.5.0-SNAPSHOT ..
Hmmm, how can i setup realm transformer on my project ?
Is there any instruction to do that ? I've tried @jtrouvere solution, but app still crashing ..
Thank you

Theoretically, 5.4.0 is supposed to work with OkBuck.

If something is failing, you need to be specific about the actual crash and stuff.

@Zhuinden okay, i got this error ..

java.lang.ExceptionInInitializerError: RealmTransformer doesn't seem to be applied. Please update the project configuration to use the Realm Gradle plugin. See https://realm.io/news/android-installation-change/
        at io.realm.RealmConfiguration.<clinit>(RealmConfiguration.java:80)
        at io.realm.RealmConfiguration$Builder.initializeBuilder(RealmConfiguration.java:501)
        at io.realm.RealmConfiguration$Builder.<init>(RealmConfiguration.java:487)
        at io.realm.Realm.init(Realm.java:273)
        at id.xcromez.what2watch.What2Watch.onCreate(What2Watch.java:23)
        at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1012)
        at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4553)
        at android.app.ActivityThread.access$1500(ActivityThread.java:151)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1364)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:135)
        at android.app.ActivityThread.main(ActivityThread.java:5254)
        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:903)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)

And the crash come from this file What2Watch.java:23 which is Realm.init(this); :

@Override
    public void onCreate() {
        super.onCreate();
        if (!BuildConfig.DEBUG) {
            Fabric.with(this, new Crashlytics());
        }
        Realm.init(this);
        RealmConfiguration realmConfiguration = new RealmConfiguration.Builder().deleteRealmIfMigrationNeeded().build();
        Realm.setDefaultConfiguration(realmConfiguration);
    }

And i put this on my build.gradle :

okbuck {
    buildToolVersion = "27.0.3"
    target = "android-26"
    buckBinary = "com.github.facebook:buck:v2018.07.23.01@pex"
    lint {
        disabled = true
    }
    experimental {
        transform = true
    }
    transform {
        transforms = [
                'debug': [
                        [transform: "io.realm.transformer.RealmTransformer",
                        ],
                ]
        ]
    }
}

Is there something that i missed ?
Thanks ..

@aldochristiaan any chance you have a small repro project that you can put on github? Will help diagnose the issue faster

@kageiit i don't have it at this moment, but i'll try to create one and come back here later ..

Have you tried with

    transform {
        transforms = [
                'appDebug' : [
                        [transform : "io.realm.transformer.RealmTransformer"]
                ],
'appRelease' : [
                        [transform : "io.realm.transformer.RealmTransformer"]
                ]
        ]
    }

    experimental {
        transform = true
    }
}

dependencies {
    transform "io.realm:realm-transformer:5.4.0"
}

@Zhuinden i got this error :

Input jars dir: /Users/bukalapak/Documents/Aldo/What2Watch/buck-out/bin/app/bin_debug#class_file_to_dex_processing/non_predexed_root/bin/java_classes_preprocess_in
Output jars dir: /Users/bukalapak/Documents/Aldo/What2Watch/buck-out/bin/app/bin_debug#class_file_to_dex_processing/non_predexed_root/bin/java_classes_preprocess_out

Exception in thread "main" java.lang.NoClassDefFoundError: org/gradle/api/Project
    at java.lang.Class.getDeclaredConstructors0(Native Method)
    at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671)
    at java.lang.Class.getConstructor0(Class.java:3075)
    at java.lang.Class.newInstance(Class.java:412)
    at com.uber.okbuck.transform.TransformRunner.runTransform(TransformRunner.java:75)
    at com.uber.okbuck.transform.CliTransform.main(CliTransform.java:96)
    at com.uber.okbuck.transform.CliTransform.main(CliTransform.java:51)
Caused by: java.lang.ClassNotFoundException: org.gradle.api.Project
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 7 more

Build failed: Command failed with exit code 1.
stderr: Exception in thread "main" java.lang.NoClassDefFoundError: org/gradle/api/Project
    at java.lang.Class.getDeclaredConstructors0(Native Method)
    at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671)
    at java.lang.Class.getConstructor0(Class.java:3075)
    at java.lang.Class.newInstance(Class.java:412)
    at com.uber.okbuck.transform.TransformRunner.runTransform(TransformRunner.java:75)
    at com.uber.okbuck.transform.CliTransform.main(CliTransform.java:96)
    at com.uber.okbuck.transform.CliTransform.main(CliTransform.java:51)
Caused by: java.lang.ClassNotFoundException: org.gradle.api.Project
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 7 more

    When running <genrule>.
    When building rule //app:bin_debug#class_file_to_dex_processing.

Here is my build.gradle file:

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {

    repositories {
        jcenter()
        google()
        mavenCentral()
        maven {
            url 'https://maven.fabric.io/public'
        }
        maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.1.3'
        classpath 'io.fabric.tools:gradle:1.+'
        classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.51'
        classpath 'com.jakewharton:butterknife-gradle-plugin:9.0.0-SNAPSHOT'
        classpath 'com.uber:okbuck:0.40.0'
        classpath 'io.realm:realm-gradle-plugin:5.4.0'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
        google()
        maven {
            url 'https://maven.fabric.io/public'
        }
        maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
    }
}

apply plugin: 'com.uber.okbuck'

okbuck {
    buildToolVersion = "27.0.3"
    target = "android-26"
//    buckBinary = "com.github.facebook:buck:v2018.07.23.01@pex"
    lint {
        disabled = true
    }
    transform {
        transforms = [
                'appDebug' : [
                        [transform : "io.realm.transformer.RealmTransformer"]
                ],
                'appRelease' : [
                        [transform : "io.realm.transformer.RealmTransformer"]
                ]
        ]
    }
    experimental {
        transform = true
    }
}

dependencies {
    transform 'io.realm:realm-transformer:5.4.0'
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

ext {
    // Sdk and tools
    minSdkVersion = 19
    targetSdkVersion = 26
    compileSdkVersion = 26
    buildToolsVersion = '27.0.3'

    // App dependencies
    supportLibraryVersion = '27.1.1'
    constraintLayoutVersion = '1.1.2'
    guavaVersion = '18.0'
    junitVersion = '4.12'
    mockitoVersion = '1.10.19'
    powerMockito = '1.6.2'
    hamcrestVersion = '1.3'
    runnerVersion = '1.0.0'
    rulesVersion = '1.0.0'
    espressoVersion = '3.0.1'
    rxjavaVersion = '2.1.3'
    rxandroidVersion = '2.0.1'
    multiDexVersion = '1.0.2'
}

@aldochristiaan In a way, that is much more interesting, because now it tries to apply the transform, but I don't know why it fails.

What is your Gradle version?

@Zhuinden i tried gradle version 4.6 , 4.7, 4.9 but it didn't work :(
The build succeed tho 馃槄

Was this page helpful?
0 / 5 - 0 ratings

Related issues

harshvishu picture harshvishu  路  3Comments

nolanamy picture nolanamy  路  3Comments

mithrann picture mithrann  路  3Comments

gpulido picture gpulido  路  3Comments

AAChartModel picture AAChartModel  路  3Comments