2017-08-19 7 views
1

J'écris cette méthode générique pour récupérer des données à partir de Firebase? Dans certains cas, obtenir null retour est valide, dans d'autres cas ne l'est pas, est-il possible de vérifier si le param générique est nullable ou non?Kotlin - Vérifie si le paramètre générique est optionnel ou non?

ex

reference.obsrveObject(User.class) 

devrait jeter si nul

reference.obsrveObject(User?.class) 

devrait appeler OnNext avec la valeur null

fun DatabaseReference.observeSingleEvent(): Observable<DataSnapshot?> { 
    return Observable.create { subscriber -> 
     val valueEventListener = object: ValueEventListener { 
      override fun onDataChange(snapshot: DataSnapshot?) { 
       subscriber.onNext(snapshot) 
       subscriber.onCompleted() 
      } 

      override fun onCancelled(error: DatabaseError?) { 
       subscriber.onError(FirebaseDatabaseThrowable(error)) 
      } 
     } 

     addListenerForSingleValueEvent(valueEventListener) 
    } 
} 

fun <T>DatabaseReference.obsrveObject(clazz: Class<T>): Observable<T> { 
    return observeSingleEvent().map { snapshot -> 
     if (snapshot != null) { 
      snapshot.getValue(clazz) 
     } 
     else { 
      // if clazz is nullable return null 
      // if clazz is not nullabel throw 
      throw Exception("") 
     } 
    } 
} 

Répondre

3

Note: Je ne l'ai pas utilisé personnellement Firebase encore si certains d'entre les exemples ci-dessous peuvent ne pas compiler mais devraient être assez proches.

Ni Class<T> ni KClass<T> ne peuvent pas être représentés car ils représentent uniquement une classe. Un KType, cependant, peut représenter "une classe avec des arguments de type facultatifs, plus nullability" et a une propriété isMarkedNullable.

Vous pouvez utiliser reified type parameters pour obtenir un KClass pour le type générique mais vous ne pouvez pas obtenir (à partir de Kotlin 1.1) un KType. Cependant, vous pouvez toujours vérifier si le type générique est nullable (nullable reified type : Kotlin) avec null is T (merci à sosite pour pointing out que l'emballage null as T dans un try/catch n'est pas nécessaire).


Avec cela, aussi longtemps que vous pouvez marquer obsrveObject comme inline, vous pouvez "vérifier pour voir si le paramètre générique est facultatif ou non":

inline fun <reified T> DatabaseReference.obsrveObject(): Observable<T> { 
    return observeSingleEvent().map { snapshot -> 
     if (snapshot != null) { 
      snapshot.getValue(T::class.java) 
     } else if (null is T) { 
      null as T 
     } else { 
      throw Exception("") 
     } 
    } 
} 

Utilisation:

databaseReference.obsrveObject<User>() // Observable<User> 
databaseReference.obsrveObject<User?>() // Observable<User?> 

Si vous ne pouvez pas utiliser une fonction inline (et donc des paramètres de type réifiés), alors vous devez pour trouver un moyen d'obtenir un KType.

Vous pouvez obtenir un KType de la returnType sur KCallable<R> mais vous pouvez également créer un KType d'un KClass<T> en utilisant createType:

User::class.createType(nullable = false) // User 
User::class.createType(nullable = true)  // User? 

La classe est ici classifier de type donc en fonction de la façon dont vous utilisez vous obsrveObject pourrait changer son type d'argument de Class<T> à KCallable<T>. Vous pouvez changer à un KType directement et créer des instances au besoin, mais je devine votre accaparement clazz actuellement du type de retour d'une propriété et je voudrais donc aller avec KCallable<T>:

fun <T : Any> DatabaseReference.obsrveObject(callable: KCallable<T>): Observable<T?> { 
    val kType = callable.returnType 
    val kClass = kType.classifier as KClass<T> 
    val clazz = kClass.java 
    return observeSingleEvent().map { snapshot -> 
     if (snapshot != null) { 
      snapshot.getValue(clazz) 
     } else if (kType.isMarkedNullable) { 
      null 
     } else { 
      throw Exception("") 
     } 
    } 
} 

Vous pouvez ensuite appeler à l'aide d'un référence à un appelable (propriété, fonction, etc.):

databaseReference.obsrveObject(session::user) 
+0

Merci, le résultat retourné doit-il être un observable de type optionnel? – aryaxt

+0

Eh bien, si vous voulez être en mesure de revenir 'null' alors vous devez soit retourner' 'Observable ou' Observable ? '. Si vous voulez le plus tard, vous devriez pouvoir 'renvoyer null'. – mfulton26

+0

J'espérais pouvoir le définir comme optionnel en cas de besoin, c'est possible dans swift, n'est-ce pas à Kotlin? par exemple des données , données , de cette façon le type générique peut être définie comme facultative ou obligatoire en tant qu'utilisateur en cas de besoin – aryaxt