mk-5 / gdx-fireapp

libGDX Firebase API
Apache License 2.0
65 stars 21 forks source link

[Database] Can't do map conversion from type: java.lang.Long #25

Closed imlutr closed 5 years ago

imlutr commented 5 years ago

Describe the bug I am trying to read a number (Long) from my Firebase Realtime Database on Android in my Kotlin+libGDX game, but I get always an exception.

To Reproduce Here is how the database looks like: database Here is the code:

GdxFIRDatabase.inst()
    .inReference("number")
    .readValue(Long::class.java)
    .then(
        Consumer {
            println(it)
        }
    )

The following exception is thrown:

pl.mk5.gdx.fireapp.exceptions.MapConversionNotPossibleException: Can't do map conversion from type: java.lang.Long
    at pl.mk5.gdx.fireapp.promises.MapMitmConverter.doMitmConversion(MapMitmConverter.java:60)
    at pl.mk5.gdx.fireapp.promises.ConverterPromise.doComplete(ConverterPromise.java:67)
    at pl.mk5.gdx.fireapp.android.database.DataSnapshotResolver.resolve(DataSnapshotResolver.java:44)
    at pl.mk5.gdx.fireapp.android.database.SnapshotValueListener.onDataChange(SnapshotValueListener.java:37)
    at com.google.firebase.database.Query$1.onDataChange(com.google.firebase:firebase-database@@17.0.0:184)
    at com.google.firebase.database.core.ValueEventRegistration.fireEvent(com.google.firebase:firebase-database@@17.0.0:75)
    at com.google.firebase.database.core.view.DataEvent.fire(com.google.firebase:firebase-database@@17.0.0:63)
    at com.google.firebase.database.core.view.EventRaiser$1.run(com.google.firebase:firebase-database@@17.0.0:55)
    at android.os.Handler.handleCallback(Handler.java:789)
    at android.os.Handler.dispatchMessage(Handler.java:98)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6944)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)

If I replace the Long with any other class, such as String (so .readValue(Long::class.java) would become .readValue(String::class.java)), while still reading the same number, without modifying the database, I'll get the following exception:

java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.String
    at ro.luca1152.gravitybox.MyGame$create$1.accept(MyGame.kt:49)
    at pl.mk5.gdx.fireapp.promises.ConsumerWrapper.accept(ConsumerWrapper.java:35)
    at pl.mk5.gdx.fireapp.promises.FuturePromise.doComplete(FuturePromise.java:180)
    at pl.mk5.gdx.fireapp.promises.FutureListenerPromise.doComplete(FutureListenerPromise.java:43)
    at pl.mk5.gdx.fireapp.promises.ConverterPromise.doComplete(ConverterPromise.java:83)
    at pl.mk5.gdx.fireapp.android.database.DataSnapshotResolver.resolve(DataSnapshotResolver.java:44)
    at pl.mk5.gdx.fireapp.android.database.SnapshotValueListener.onDataChange(SnapshotValueListener.java:37)
    at com.google.firebase.database.Query$1.onDataChange(com.google.firebase:firebase-database@@17.0.0:184)
    at com.google.firebase.database.core.ValueEventRegistration.fireEvent(com.google.firebase:firebase-database@@17.0.0:75)
    at com.google.firebase.database.core.view.DataEvent.fire(com.google.firebase:firebase-database@@17.0.0:63)
    at com.google.firebase.database.core.view.EventRaiser$1.run(com.google.firebase:firebase-database@@17.0.0:55)
    at android.os.Handler.handleCallback(Handler.java:789)
    at android.os.Handler.dispatchMessage(Handler.java:98)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6944)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)

Which would mean that what I am getting from the database really is a Long (I guess).

However, the following (reading a String) works just fine:

GdxFIRDatabase.inst()
    .inReference("string")
    .readValue(String::class.java)
    .then(
        Consumer {
            println(it)
        }
    )

Expected behavior I'd expect to be able to read both Strings and Longs, not only Strings.

Platform:

Smartphone:

mk-5 commented 5 years ago

Thanks for reporting :) I'll check that, and I'll let you know.

It may be some gdxfireapp API<>KOTLIN related problem because Long value reading should work fine

mk-5 commented 5 years ago

Hello, I've checked that and that method causes the problem in your case:

public static boolean isJavaCoreClass(Class<?> type) {
    return type.getName().startsWith("java");
}

It looks like it returns false for Long ... and API thinks that you put some POJO class (not java core class) as wanted data type - readValue method argument.

So, it looks like something is wrong with Kotlin->Java transformation, I also checked if read Long value works on Java - and it works.

Could you check how the compiled Java code looks like?

mk-5 commented 5 years ago

oookay :) I think I found the problem, take a look here: https://pl.kotl.in/Wur_3CkLd

Long::class.java.getName() returns "long" in Kotlin, without package name String::class.java.getName() returns "java.lang.String" - same as Java

mk-5 commented 5 years ago

okay, so I've pushed FIX for that, please looking forward to version 2.1.3

imlutr commented 5 years ago

Yup! That was it! Sorry for not replying about the compiled Java code, I just got home :).

The following code now works:

GdxFIRDatabase.inst()
    .inReference("number")
    .readValue(java.lang.Long::class.java)
    .then(
        Consumer {
            println("$it")
        }
    )

(replacing readValue(Long::class.java) with readValue(java.lang.Long::class.java))

Thanks! ❤️

mk-5 commented 5 years ago

💪 💪 💪 great :)

anyway, I've adopted API to recognize kotlin names as well - but it is still building ... high traffic at Travis :)