Is it Kotlin issue or i'm missing something?

I have imported my db in several structures using cblite-tool…

import ../db/flickr/

one way of building the db was using the couchbase example on their android-java tutorial

[{"photo":{"id":"51334404495","owner":"131209910@N02","secret":"a0b873fda8","server":"65535","farm":66,"title":"Evening mood...","ispublic":1,"isfriend":0,"isfamily":0,"url_s":"https:\/\/live.staticflickr.com\/65535\/51334404495_a0b873fda8_m.jpg","height_s":125,"width_s":240}},
{"photo":{"id":"51333393876","owner":"134230993@N02","secret":"570648e7a0","server":"65535","farm":66,"title":"Blue denim...","ispublic":1,"isfriend":0,"isfamily":0,"url_s":"https:\/\/live.staticflickr.com\/65535\/51333393876_570648e7a0_m.jpg","height_s":180,"width_s":240}},
{"photo":{"id":"51331253286","owner":"39652177@N04","secret":"07494972e6","server":"65535","farm":66,"title":"Great blue heron","ispublic":1,"isfriend":0,"isfamily":0,"url_s":"https:\/\/live.staticflickr.com\/65535\/51331253286_07494972e6_m.jpg","height_s":189,"width_s":240}},...

after that i run the command reindex on cblite tool.

i used these 2 ways to get them to the app, but bother weren’t useful

i created a model for the data in db

data class photo(
    val owner: String,
    val server: String,
    val height_s: String,
    val width_s: String,
    val url_s: String,
    val ispublic: String,
    val isfriend: String,
    val farm: String,
    var id: String,
    val secret: String,
    val title: String,
    val isfamily: String
)

Query:

 val listQuery: Query = QueryBuilder.select(SelectResult.all())
            .from(DataSource.database(database))

and tried a for loop to get the data using their keys into the front end (i’m working on JetPack compose)

 for (result in listQuery.execute().allResults()){
        println(result.getDictionary(0).getString("owner"))
    }

but that didn’t work, i tried to print the result in console for once type but the app crash every time.

java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.couchbase.lite.Dictionary.getString(java.lang.String)' on a null object reference

only when i get it as an array that i get the whole data on the same index

 for (result in listQuery.execute().allResults()){
        println(result.getArray(0).toList())
    }

it shows like this:

I/System.out: [{photo={owner=131209910@N02, server=65535, height_s=125, width_s=240, url_s=https://live.staticflickr.com/65535/51334404495_a0b873fda8_m.jpg, ispublic=1, isfriend=0, farm=66, id=51334404495, secret=a0b873fda8, title=Evening mood..., isfamily=0}}, {photo={owner=134230993@N02, server=65535, height_s=180, width_s=240, url_s=https://live.staticflickr.com/65535/51333393876_570648e7a0_m.jpg, ispublic=1, isfriend=0, farm=66, id=51333393876, secret=570648e7a0, title=Blue denim..., isfamily=0}}, {photo={owner=39652177@N04, server=65535, height_s=189, width_s=240, url_s=https://live.staticflickr.com/65535/51331253286_07494972e6_m.jpg, ispublic=1, isfriend=0, farm=66, id=51331253286, secret=07494972e6, title=Great blue heron, isfamily=0}}...

but i can’t convert this array into List<photo> it always remains MutableList<Any?>
even if i cast it. or try to create a loop to add it into a list the app crash.

the second way was using a document to get the data and it is the same issue with the list type and items within the array.

what is missing or wrong???

I do not know this area of the Couchbase product family nor have I used Kotlin, but I have used Java extensively. From my naive perspective I think perhaps the problem in the attempted cast from MutableList<Any?> to List is that perhaps Kotlin disallows casting from a mutable to an immutable type, as a cast does not create a new object, so another thread that still has a reference to the (only) object as MutableList could change it, thus violating the immutability of List. Have you tried casting it to MutableList instead of List? Presumably the rest of your code needs the list entries to be recognized as objects of type photo, whereas it may not depend on whether they reside in a List or a MutableList due to polymorphism.

1 Like

Good Morning

thank you so much for your response… often people turn their back to my posts i wont know if i did something stupid or there is a real issue here…

please bare with me, because i think this issue is important. (ALMOST) every app has a recyclerview and google created JetPack compose for Kotlin only (till now at least).

if we can’t get arrays/lists in Kotlin ( because i think it is a Kotlin issue)why would we use Couchbase for future jetpack apps?

I tried to do as you said

val query = QueryBuilder
        .select(SelectResult.all())
        .from(DataSource.database(database))
    val result = query.execute().allResults()
    println("Array Result: ${result[0].getArray(0).toList()}")
    var photosList: MutableList<photo>
        photosList =result[0].getArray(0).toList() as MutableList<photo>

I printed the result before using it in the photoList and i got the items

I/System.out: Array Result: [{owner=131209910@N02, server=65535, height_s=125, width_s=240,
url_s=https://live.staticflickr.com/65535/51334404495_a0b873fda8_m.jpg, ispublic=1, isfriend=0, farm=66, id=51334404495, secret=a0b873fda8, title=Evening mood…, ]

I also tried doing it with this structure:

I/System.out: Array Result: [{photo={owner=131209910@N02, server=65535, height_s=125, width_s=240, url_s=https://live.staticflickr.com/65535/51334404495_a0b873fda8_m.jpg, ispublic=1, isfriend=0, farm=66, id=51334404495, secret=a0b873fda8, title=Evening mood…, isfamily=0}}…]

cbLite report:

(cblite) info -v
Database: …/db/primary-directory.cblite2/
Size: 60KB (doc bodies: 2KB, doc metadata: 34 bytes, blobs: 0 bytes)
Documents: 1, last sequence #1
UUIDs: public 528c53241b5747898d015613bd52fed2, private 32fa46af86264f988241324f009ce874
Shared keys: 13: [“photo”, “id”, “owner”, “secret”, “server”, “farm”, “title”, “ispublic”, “isfriend”, “isfamily”, “url_s”, “height_s”, “width_s”]
(cblite)

and then i got this error: (for both structures)

D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.saher.couchbaseprebuiltdb, PID: 5930
    java.lang.ClassCastException: java.util.HashMap cannot be cast to com.saher.couchbaseprebuiltdb.model.photo
        at com.saher.couchbaseprebuiltdb.MainActivityKt$Greeting$1$1$invoke$$inlined$items$default$2.invoke(LazyDsl.kt:104)
        at com.saher.couchbaseprebuiltdb.MainActivityKt$Greeting$1$1$invoke$$inlined$items$default$2.invoke(LazyDsl.kt:103)

did i made anything wrong this way? do you agree it is a Kotlin issue?

The problem has nothing at all to do with Kotlin. For some result set, getDictionary(0) is returning null. That is, probably, because the result doesn’t have a dictionary at index 0. It probably has an Array. … which is why, getting the the Array at index 0 works.

You can’t cast MutableList<Any?> into a List because it is a MutableList<Dictionary>. You are going to have to convert the Dictionaries to Photos, yourself.

And finally: you say .“please bare with me”. This is a family-oriented forum and we do not encourage people getting bare, either individually or in groups :stuck_out_tongue_winking_eye:

1 Like

Thank you @blake.meike for filling in more detailed info. Java already has pretty strict type casting rules, and it sounds like Kotlin adds its own layer of requirements on top of that. :slight_smile:

1 Like

okey… no one needs to bare… be patient… I’m not a native english speaker…

You can’t cast MutableList<Any?> into a List because it is a MutableList. You are going to have to convert the Dictionaries to Photos, yourself.

How to do that?

final Dictionary dict = resultArray.getDictiionary(i);
final Photo photo = new Photo(dict.get("id"), dict.get("height_s"), dict.get("width_s"), ...)
1 Like

I think i tried that in the first place when i followed the example on the tutorial website for Android-Java…
(plz tell me if i did something wrong)

Data model in db:

{Department=BRANDY, cost=0, price=12.99, Barcode=85000024041, name=E&J Apple Brandy - 750ml}

val query = QueryBuilder
            .select(SelectResult.all())
            .from(DataSource.database(database))

        val rs = query.execute()

for (result in rs) {

    val dictionary = result.getDictionary(0)

                    println(dictionary.getString("Department")!!)
                    println(dictionary.getString("name")!!)
                    println(dictionary.getString("cost")!!)
                    println(dictionary.getString("price")!!)
                    println(dictionary.getString("Barcode")!!)

    }

and i got this error

java.lang.RuntimeException: Unable to create application com.saher.couchbaseprebuiltdb.MyApplication: java.lang.NullPointerException: Attempt to invoke virtual method ‘java.lang.String com.couchbase.lite.Dictionary.getString(java.lang.String)’ on a null object reference

(I removed a part that i solved on my own from below, i missed one thing from it)

@Saher.alsous

That looks like result.getDictionary(0) must be returning null, so then dictionary.getString(…) throws a null pointer exception. Blake mentioned this in his earlier reply – result seems to have an Array at position 0 so result.getArray(0) returns non-null but result.getDictionary(0) returns null.

i did that…but i got the same result… it seems that I’m not get something fundamental with this… wont bother you anymore.

thank you for your time.

                val query = QueryBuilder
            .select(SelectResult.all())
            .from(DataSource.database(database))

        val rs = query.execute()

for (result in rs) {

    val dictionary = result.getArray(0)

                    println("Index item: "+dictionary.getString(0))
//                    println("Index item: "+dictionary.getString(1))
//                    println("Index item: "+dictionary.getString(2))
//                    println("Index item: "+dictionary.getString(3))
//                    println("Index item: "+dictionary.getString(4))

    }

java.lang.RuntimeException: Unable to create application com.saher.couchbaseprebuiltdb.MyApplication: java.lang.NullPointerException: Attempt to invoke virtual method ‘java.lang.String com.couchbase.lite.Array.getString(int)’ on a null object reference

@Saher.alsous In this case dictionary == null again, so position 0 must not have an Array in it in this run. You might try adding some debugging prints such as dumping the raw value of result and its type. (I don’t know Kotlin so can’t help with how to do that.) Also check that your database actually has the correct data in it that you expect this query to retrieve. Another thought is that your query may be retrieving some documents that are of a different form than you are expecting, in addition to the documents you are expecting, so the query may need to add a predicate to select only the docs of the type you want.

Well, I can get the list as a whole and per index using both the dictionary and array… but i could never access a single key within it… this is weird… i changed the structure of the db several times but it is always the same with me.
also when i make a query that includes .where(…) and insert keys and values the query returns nothing… as if it didn’t find any key or value… there must be something hidden that I can’t see… I may create a java helper for this… will see

thank you both so much

all the issue was in the .select() method.

when using .select(SelectResult.all()) the array was treated as a single item, keys weren’t available to be used to get the values. that is why i got the NullPointerException (weird or normal?)

therefore i had to specify all the keys in the select method to access their values in the result.

val query = QueryBuilder
            .select(
                SelectResult.expression(Meta.id),
                SelectResult.property("owner"),
                SelectResult.property("secret"),
                SelectResult.property("server"),
                SelectResult.property("farm"),
                SelectResult.property("title"),
                SelectResult.property("ispublic"),
                SelectResult.property("isfriend"),
                SelectResult.property("isfamily"),
                SelectResult.property("url_s"),
                SelectResult.property("height_s"),
                SelectResult.property("width_s"),
            )
            .from(DataSource.database(database))