Erreur cotlin étrange checkNotNullParameter

jack_the_beast

nous avons reçu un crash sur Firebase pour une méthode kotlin :

Fatal Exception: java.lang.NullPointerException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkNotNullParameter, parameter code
       at [redacted].DeliveryMethod.<init>(:2)
       at [redacted].DeliveryMethodsUpdater$addSingleDMInAd$clientCall$1.invokeSuspend(DeliveryMethodsUpdater.kt:121)
       at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
       at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
       at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
       at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:738)
       at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
       at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)

le modèle est celui-ci :

class DeliveryMethod() {
    lateinit var code: String
    lateinit var name: String
    lateinit var description: String

var isAddressRequired: Boolean? = null
var image: JSONObject? = null
var isDefault: Boolean = false

constructor(code: String) : this() {
    this.code = code
}

constructor(code: String, name: String, description: String, image: JSONObject? = null) : this() {
    this.code = code
    this.name = name
    this.description = description
    this.image = image
}
}

et la méthode :

private suspend fun addSingleDMInAd(
        adId: Long,
        deliveryMethodCode: String
    ): JoinAdDeliveryMethod? {
        var addedDeliveryMethod: JoinAdDeliveryMethod? = null
        val clientCall = GlobalScope.async(Dispatchers.IO) {
            val cd = CountDownLatch(1)
            Client.getInstance().addDeliveryMethodInAd(
                adId,
                DeliveryMethod(deliveryMethodCode),
                object : NetworkCallback<JoinAdDeliveryMethod> {
                    override fun onSuccess(result: JoinAdDeliveryMethod) {
                        addedDeliveryMethod = result
                        cd.countDown()
                    }

                    override fun onFailure(err: NetworkError?) {
                        addedDeliveryMethod = null
                        cd.countDown()
                    }
                }
            )
            cd.await()
        }
        clientCall.await()
        return addedDeliveryMethod
    }

maintenant, je comprends que le constructeur pour DeliveryMethodest appelé avec une nullvaleur pour code, mais je ne comprends pas pourquoi l'exception n'apparaît qu'à ce stade. Comme vous pouvez le voir, le paramètre de méthode est également marqué comme non nul, tout comme les méthodes précédentes. L'exception ne devrait-elle pas être levée bien avant d'arriver à l'appel du constructeur pour DeliveryMethod?

Joffrey

L'exception ne devrait-elle pas être levée bien avant d'arriver à l'appel du constructeur pour DeliveryMethod ?

Dans Kotlin, il n'est pas possible qu'un paramètre non nul reçoive une valeur nulle au moment de l'exécution (car le code n'aurait pas été compilé en premier lieu). Cependant, cela peut se produire si la valeur est transmise depuis Java.

C'est pourquoi le compilateur Kotlin génère des vérifications nulles (avec l'échec intrinsèque checkNotNullParameterque vous voyez ici) uniquement dans les méthodes publiques/protégées/internes non suspendues , pour éviter toute utilisation abusive de Java. Il est inutile de le faire dans les méthodes privées ou suspendues, car elles ne peuvent être appelées que depuis Kotlin (généralement), et cela ajouterait une surcharge qui pourrait ne pas être acceptable dans un code sensible aux performances.

C'est pourquoi l'appel addSingleDMInAdn'échoue pas avec cette erreur. Cela dit, il serait intéressant de voir comment vous obtenez la valeur nulle ici, car généralement les vérifications à la surface de l'API publique sont suffisantes. Y a-t-il une réflexion ou un casting dangereux impliqué ici ?

De plus, la façon dont votre modèle est configuré est assez étrange. Il semble que le lateinitmente car selon le constructeur utilisé, les propriétés peuvent en fait ne pas être définies du tout. Il serait plus sûr de les marquer comme nullables pour tenir compte du moment où les utilisateurs de cette classe ne définissent pas la valeur de ces propriétés. En faisant cela, vous n'aurez même pas besoin de tous les constructeurs secondaires, et vous pouvez simplement utiliser les valeurs par défaut :

class DeliveryMethod() {
    var code: String? = null,
    var name: String? = null,
    var description: String? = null,
    var image: JSONObject? = null,
) {
    var isAddressRequired: Boolean? = null
    var isDefault: Boolean = false
}

Autres choses à noter sur addSingleDMInAd:

  • ne pas utiliser GlobalScopedans ce cas. Si vous devez exécuter des coroutines de courte durée, fournissez-leur une portée plus petite qui est annulée lorsque le travail n'est plus nécessaire - cela garantit qu'aucune coroutine ne fuit. Vous pouvez en savoir plus sur les pièges potentiels GlobalScopeet les remplacements possibles dans son propre doc . Cela dit, vous ne devriez probablement pas du tout démarrer une coroutine ici, voir le point suivant.

  • n'utilisez pas async {}si vous utilisez await()juste après - il est inutile de démarrer quelque chose d'asynchrone si vous l'attendez juste là. Si vous souhaitez basculer le contexte sur IO, utilisez à la withContext(Dispatchers.IO) { ... }place. Cela dit, vous ne devriez même pas avoir besoin d'utiliser le répartiteur IO ici, voir le point suivant.

  • ne pas utiliser CountDownLatchà cette fin. La bonne façon d'encapsuler une API asynchrone en tant que suspendfonction pour les coroutines est d'utiliser suspendCancellableCoroutine (vérifiez sa doc, elle fournit un exemple sur la façon de l'utiliser). Une fois que vous l'utilisez, il n'y a plus besoin de Dispatchers.IOcar il ne bloquera plus le thread actuel.

Cet article est collecté sur Internet, veuillez indiquer la source lors de la réimpression.

En cas d'infraction, veuillez [email protected] Supprimer.

modifier le
0

laisse moi dire quelques mots

0commentaires
connexionAprès avoir participé à la revue

Articles connexes

TOP liste

  1. 1

    Microsoft.WebApplication.targets

  2. 2

    Exporter la table de l'arborescence vers CSV avec mise en forme

  3. 3

    Spring @RequestParam DateTime format comme ISO 8601 Date Heure facultative

  4. 4

    Comment analyser un hachage Ruby plat en un hachage imbriqué?

  5. 5

    Passer la taille d'un tableau 2D à une fonction ?

  6. 6

    Comment créer une nouvelle application dans Dropbox avec des autorisations complètes

  7. 7

    Algorithme: diviser de manière optimale une chaîne en 3 sous-chaînes

  8. 8

    Laravel SQLSTATE [HY000] [1049] Base de données inconnue 'previous_db_name'

  9. 9

    comment supprimer "compte de connexion google" à des fins de développement - actions sur google

  10. 10

    php ajouter et fusionner des données de deux tables

  11. 11

    Créer un système Buzzer à l'aide de python

  12. 12

    Existe-t-il un moyen de voir si mon bot est hors ligne ?

  13. 13

    Comment changer la couleur de la police dans R?

  14. 14

    Déplacement des moindres carrés d'ajustement pour les déplacements de points ayant des problèmes

  15. 15

    impossible d'obtenir l'image d'arrière-plan en plein écran dans reactjs

  16. 16

    Comment vérifier si un utilisateur spécifique a un rôle? Discord js

  17. 17

    comment afficher un bouton au-dessus d'un autre élément ?

  18. 18

    Comment choisir le nombre de fragments et de répliques Elasticsearch

  19. 19

    Comment ajouter une entrée à une table de base de données pour une combinaison de deux tables

  20. 20

    optimiser les opérations du serveur avec elasticsearch: traitement des filigranes de disque bas

  21. 21

    Comment analyser un fichier avec un tableau d'objets JSON en utilisant Node.js?

chaudétiquette

Archive