objectbox / objectbox-java

Android Database - first and fast, lightweight on-device vector database
https://objectbox.io
Apache License 2.0
4.41k stars 303 forks source link

Support initialization magic (transformer) for plain Kotlin projects #440

Open thanhhai08sk opened 6 years ago

thanhhai08sk commented 6 years ago

Issue Basics

Reproducing the bug

Description

I want to extract a common module (all objectBox usage are here) from and Android app so that it can be used for TornatoFX app (Kotlin) as well. When I set up the module as an Android library module, the Android app run fine but when I try to remove all the Android related stuff, gradle build produces logs like this:

Warning: cursor transformer did not find entity class org.de_studio.diary.appcore.data.objectBox.TodoOB

When I run the app, I can't put entity with ToMany relation into the box. I can't attach to the box as well:

java.lang.IllegalArgumentException: io.reactivex.exceptions.OnErrorNotImplementedException: lateinit property places has not been initialized

Seems like only entities with relation include in the logs.

I read the document, tried many way but can't get rid of the warning. Below is my module's settings.gradle file. Did I miss anything?

Code

apply plugin: 'java-library'
apply plugin: 'application'
apply plugin: 'kotlin'
apply plugin: 'kotlin-kapt'
apply plugin: 'net.ltgt.apt-idea'
apply plugin: 'io.objectbox'

kapt {
    arguments {
        arg("objectbox.debug", true)
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    api "io.reactivex.rxjava2:rxjava:2.1.1"
    api "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
    api 'com.artemzin.rxjava:proguard-rules:1.2.10.0'
    api 'com.jakewharton.timber:timber:4.5.1'
    api 'com.jakewharton.rxrelay2:rxrelay:2.0.0'
    api 'com.gojuno.koptional:koptional:1.2.0'
    api 'com.gojuno.koptional:koptional-rxjava2-extensions:1.2.0'
    api 'net.danlew:android.joda:2.9.9.1'
    api 'com.google.code.gson:gson:2.8.0'
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"

    api "io.objectbox:objectbox-kotlin:$objectboxVersion"
    kapt "io.objectbox:objectbox-processor:$objectboxVersion"

    implementation "io.objectbox:objectbox-java:$objectboxVersion"
}

tasks.withType(JavaCompile) {
    options.compilerArgs += [ "-Aobjectbox.debug=true" ]
}

sourceSets {
    main {
        java {
            srcDir 'src/main/java'
            srcDir 'build/generated/source/kapt/main'
        }
    }
}

sourceCompatibility = "1.8"
targetCompatibility = "1.8"

Please let me know if you need more information. I will make a sample project if needed. Thanks!

greenrobot-team commented 6 years ago

ObjectBox currently does not support "initialization magic" of relation fields/properties for plain-Kotlin projects, only for Android+Kotlin or plain-Java projects.

Try to initialize them yourself similar as described for local unit tests:

@Entity
public class Customer {
    // normally transformer would add init code, but need to manually for local unit tests
    ToOne<Order> lastOrder = new ToOne<>(this, Customer_.lastOrder);
    ToMany<Order> orders = new ToMany<>(this, Customer_.orders);
    // normally transformer would add field, but need to manually for local unit tests
    transient BoxStore __boxStore;
    ...
}

Or use an Android library module instead. -ut

thanhhai08sk commented 6 years ago

Didn't know about the magic before. Thanks for helping me out!

greenrobot-team commented 6 years ago

To support this we need to know where to hook up our transformer tasks and which inputs/outputs to use. For Android Local Unit tests we do per variant:

testVariant.javaCompile.dependsOn(transformTask)
transformTask.mustRunAfter(variant.javaCompile)

and use variant.javaCompile.destinationDir and kotlinCompile.destinationDir as input/output.

We can get the Kotlin compile task at runtime by name, the naming scheme is promised in the docs. (Also here.)

Currently the Kotlin spec has no official docs on how the compiler works and how tasks are set up. This leaves inspecting the Kotlin plugin source.

We should support mixed Java/Kotlin as well as Kotlin only projects. IIRC the plugin sets up tasks differently if there is no Java plugin.

Update: Interesting part in Kotlin2JvmSourceSetProcessor#doTargetSpecificProcessing. Done for each source set (sourceSets?all{ }).

-ut