如果您不确定某个值是否可以为null,则从API处理可能的null值 [英] Handling possible null values from an API if you are not sure if a value could be null

查看:82
本文介绍了如果您不确定某个值是否可以为null,则从API处理可能的null值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

moshi 1.11.0

我有以下来自sportsapidata API的数据类

I have the following data class that is being populated from the sportsapidata API

@JsonClass(generateAdapter = true)
data class PlayerEntity(
        @Json(name = "player_id")
        val playerId: Int,
        val firstname: String,
        val lastname: String,
        val birthday: String,
        val age: Int,
        val weight: Int,
        val height: Int,
)

问题是,对于某些值,来自API的数据可能为空,并且想知道在创建数据类时的最佳做法是什么.

The question is, the data from the API could be null for some values and wondering what is the best practice when creating the data class.

下面的数据显示 weight height 为空,但在其他情况下,其他值也可能为空.

Below the data is showing null for weight and height, but in other cases it could be for other values as well.

  "data": [
    {
      "player_id": 2497,
      "firstname": "Jay-Alistaire Frederick",
      "lastname": "Simpson",
      "birthday": "1988-12-01",
      "age": 32,
      "weight": 85,
      "height": 180,
    },
    {
      "player_id": 2570,
      "firstname": "Simranjit",
      "lastname": "Singh Thandi",
      "birthday": "1999-10-11",
      "age": 21,
      "weight": null,
      "height": null,
    }]

最好为所有值使用 nullable类型,以便可以将null分配给它们

Would it be better to have nullable types for all the values so that null can be assigned to them

@JsonClass(generateAdapter = true)
data class PlayerEntity(
        @Json(name = "player_id")
        val playerId: Int?,
        val firstname: String?,
        val lastname: String?,
        val birthday: String?,
        val age: Int?,
        val weight: Int?,
        val height: Int?,
)

推荐答案

问题来自于以下事实,即 PlayerEntity 承担两种职责:

The problem comes from the fact, that the PlayerEntity mixes two responsibilities:

  • 这是一个数据传输对象.因此,它应该遵守任何API合同.如果允许所有字段为空,则这些字段应为可空.
  • 它是域模型的一部分(我假设给定 Entity 后缀).因此,它应遵守您的域规则.绝对不希望仅因为API允许它们而具有可为空的字段.
  • It's a data transfer object. As such it should adhere to whatever the API contract is. If it allows all the fields to be null, then the fields should be nullable.
  • it's a part of the domain model (I assume so given the Entity postfix). As such it should adhere to your domain rules. Definitely you don't want to have nullable fields just because the API allows them.

这种混合职责是一种捷径.只要两个模型都非常相似并且您不牺牲域的一致性,就可以接受.

This kind of mixed responsibilities is a kind of a shortcut. It is acceptable as long as the two models are fairly similar and you don't sacrifice your domain consistency.

如果未设置 weight 字段,您的域逻辑是否仍然起作用?大概吧.然后继续,使其可为空.这就是可空类型的用途.他们清楚地表明该价值可能会丢失.我在这里不使用任何默认值:每次使用该字段时,您都需要记住检查该字段值是否等于默认值(在 wight = 0 我想是您的域).可空类型会使编译器提醒您有关检查的信息.

Is your domain logic still functional if the weight field is not set? I guess so. Then go ahead, make it nullable. That's what the nullable types are for. They clearly communicate that the value might be missing. I wouldn't use any default value here: it would require you to remember to check if the field value is equal to the default value every time you use it (wight = 0 does not make much sense in your domain I guess). Nullable types will make the compiler remind you about the checks.

如果未设置 playerId 字段,您的域逻辑是否仍然起作用?我觉得不是.然后它就不能为空,您需要拒绝该值.拒绝它的简单方法将使字段不可为空.该库(在您的情况下为moshi)将引发一些丑陋的错误,您需要对其进行处理.

Is your domain logic still functional if the playerId field is not set? I guess no. Then it should not be nullable, you need to reject the value. The simples way of rejecting it would making the filed non-nullable. The library (moshi in your case) will throw some ugly error that you will need to deal with.

如何处理一个更复杂的场景,比如说 age ?如其中一项评论中所述,可以从生日计算得出.但是,如果API有时返回 birthday ,有时返回 age ,有时返回两者,但有时都没有返回该怎么办?假设您实际上对 age 字段感兴趣,但是如果没有它,您仍然可以活下去.嗯,逻辑变得有点复杂,您绝对不想在每次访问 age 字段时都进行处理.在这种情况下,请考虑将 PlayerEntity 分为 PlayerEntity PlayerDto ,引入一种

How about some more complex scenario, let's say the age? As mentioned in one of the comments, it could be calculated from the birthday. But what if the API sometimes returns birthday, sometimes age, sometimes both and yet sometimes none of them? Let's say you are actually interested in the age field but you can still live without it. Well, the logic is getting a bit complex and you definitely don't want to deal with it every time you access the age field. In that case, consider splitting the PlayerEntity into PlayerEntity and PlayerDto, introducing a kind of an anti-corruption-layer (a mapper simply speaking). The key point is to keep your domain pure and to deal with all the uncertainties at the boundaries. If you prefer not to have two Player classes, you might consider creating a custom-type-adapter.

更新:

关于其中一项评论的主张:

Regarding a claim from one of the comments:

一个空值=一个不存在的值.如果构造函数接收到null,则类构造函数本身将分配默认值,这是Kotlin的事情,无论是moshi,jackson还是gson都无关紧要.

A null value = an absent value. The class constructor itself will asign the default value if it receives null, this is a Kotlin thing, it doesn't matter if it is mos jackson or gson.

绝对不是这样,null和absent都不一样.无论是对于Kotlin本身,还是对于Moshi,都是如此.请考虑以下代码段:

It's definitely not the case, null and absent are not the same. Neither for Kotlin itself, nor for Moshi. Consider the following snippet:

data class Data(var field: String? = "Test")

@Test
fun test() {

    val moshi = Moshi.Builder().addLast(KotlinJsonAdapterFactory()).build()
    val jsonAdapter = moshi.adapter(Data::class.java);

    println("Kotlin constructor, missing field: ${Data()}")
    println("Kotlin constructor, null: ${Data(null)}")
    println("Moshi, missing field: ${jsonAdapter.fromJson("{}")}")
    println("Moshi, null: ${jsonAdapter.fromJson("""{"field": null}""")}")
}

Kotlin constructor, missing field: Data(field=Test)
Kotlin constructor, null: Data(field=null)
Moshi, missing field: Data(field=Test)
Moshi, null: Data(field=null)

如果 field 是不可为空的,则即使该字段具有默认值,尝试反序列化 {"field":null} 也会引发异常.

If the field was non-nullable, an attempt to deserialize {"field": null} would throw an exception, even though the field has a default value.

这篇关于如果您不确定某个值是否可以为null,则从API处理可能的null值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆