When using Kotlin to work with Firebase database, I can't seem to retrieve a value of type List<String>
if I use a GenericTypeIndicator
as follows:
snap.getValue(object : GenericTypeIndicator<List<String>>() {})
It produces an exception from the Firebase SDK as follows:
com.google.firebase.database.DatabaseException: Generic wildcard types are not supported
at com.google.android.gms.internal.zzbtg.zza(Unknown Source)
at com.google.android.gms.internal.zzbtg.zza(Unknown Source)
at com.google.android.gms.internal.zzbtg.zza(Unknown Source)
at com.google.android.gms.internal.zzbtg.zza(Unknown Source)
at com.google.firebase.database.DataSnapshot.getValue(Unknown Source)
However, if I call it from Java, as follows, it works:
snap.getValue(new GenericTypeIndicator<List<String>>() {})
I was guessing that it has to do with type reifying, so I did this:
inline fun <reified T> genericType() = object: GenericTypeIndicator<T>() {}
val stringListIndicator = genericType<List<String>>()
snap.getValue(stringListIndicator)
but the same exception happened.
Why is it so?
Edit: I tried to decompile both Java and Kotlin versions using jadx-0.6.1.
Java source:
public class Randommmm {
private static final GenericTypeIndicator<List<String>> ti = new GenericTypeIndicator<List<String>>() {
};
public static List<String> x(DataSnapshot snap) {
return snap.getValue(ti);
}
}
Decompiled:
public class Randommmm {
private static final GenericTypeIndicator<List<String>> ti = new C12761();
static class C12761 extends GenericTypeIndicator<List<String>> {
C12761() {
}
}
public static List<String> m48x(DataSnapshot snap) {
return (List) snap.getValue(ti);
}
}
Kotlin source (1):
object Randommmm {
private val ti = object : GenericTypeIndicator<List<String>>() {
}
fun x(snap: DataSnapshot): List<String> {
return snap.getValue(ti)
}
}
Decompiled:
public final class Randommmm {
public static final Randommmm INSTANCE = null;
private static final Randommmm$ti$1 ti = null;
static class C12761 extends GenericTypeIndicator<List<String>> {
C12761() {
}
}
static {
Randommmm randommmm = new Randommmm();
}
private Randommmm() {
INSTANCE = this;
ti = new Randommmm$ti$1();
}
@NotNull
public final List<String> m48x(@NotNull DataSnapshot snap) {
Intrinsics.checkParameterIsNotNull(snap, "snap");
Object value = snap.getValue(ti);
Intrinsics.checkExpressionValueIsNotNull(value, "snap.getValue(ti)");
return (List) value;
}
}
public final class Randommmm$ti$1 extends GenericTypeIndicator<List<? extends String>> {
Randommmm$ti$1() {
}
}
Kotlin source (2) using ArrayList
as suggested by Doug:
object Randommmm {
private val ti = object : GenericTypeIndicator<ArrayList<String>>() {
}
fun x(snap: DataSnapshot): List<String> {
return snap.getValue(ti)
}
}
Decompiled:
public final class Randommmm {
public static final Randommmm INSTANCE = null;
private static final Randommmm$ti$1 ti = null;
static class C12761 extends GenericTypeIndicator<List<String>> {
C12761() {
}
}
static {
Randommmm randommmm = new Randommmm();
}
private Randommmm() {
INSTANCE = this;
ti = new Randommmm$ti$1();
}
@NotNull
public final List<String> m48x(@NotNull DataSnapshot snap) {
Intrinsics.checkParameterIsNotNull(snap, "snap");
Object value = snap.getValue(ti);
Intrinsics.checkExpressionValueIsNotNull(value, "snap.getValue(ti)");
return (List) value;
}
}
public final class Randommmm$ti$1 extends GenericTypeIndicator<ArrayList<String>> {
Randommmm$ti$1() {
}
}
In Kotlin,
val ti = object : GenericTypeIndicator<List<String>>() {}
is generated as (in Java):
SyntethicClass ti = new SyntethicClass();
public final class SyntethicClass extends GenericTypeIndicator<List<? extends String>> {}
Notice the wildcard ? extends String
instead of just plain String
.
See https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html#variant-generics for explanation.
In order to prevent that, annotate the type parameter with @JvmSuppressWildcards
:
val ti = object : GenericTypeIndicator<List<@JvmSuppressWildcards String>>() {}
This gets super ugly, but it works. Alternatively, use ArrayList
as per Doug's answer.
Try changing this line:
snap.getValue(object : GenericTypeIndicator<List<String>>() {})
To this:
snap.getValue(object : GenericTypeIndicator<ArrayList<String>>() {})
It works for me, but I don't know why.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With