【问题标题】:Translate API response to nullable String将 API 响应转换为可为空的字符串
【发布时间】:2020-11-10 18:40:13
【问题描述】:

我使用的 API 返回(在其他字段中)一个必需的 telephone1 和一个可选的 telephone2。但是,我获取的 JSON 始终包含两个字段,并且缺少的条目显示为空字符串。

{
   "telephone1": "+1 555 1234",
   "telephone2": ""
}

当响应映射到 pojo 时,是否最好将空字符串转换为 null?这样:

data class(
   val telephone1: String,
   val telephone2: String?
}

对我来说,这更好地传达了可能的状态。不过,我应该吗?有缺点吗?

【问题讨论】:

  • 您实际使用哪个 API?
  • 我工作的一家大公司的内部 API。这意味着它不是公开的,但我也没有影响它。
  • 你问“如何实现这个(反)序列化?”或“什么更好地强调缺少字符串值 - null 或空字符串?”
  • 更好的方法是强调不存在字符串值 - null 或空字符串。如果后端开发人员的选择——他选择了一个空字符串——会对我的选择产生任何影响。

标签: oop kotlin design-patterns software-design


【解决方案1】:

乍一看,问题归结为进一步数据处理之前的不同检查:x == nullx.isEmpty()。但是,虽然可空性检查通常由 kotlin 编译器强制执行(与 unemptiness 不同),但它似乎是一个更好的选择。

但在某些情况下,null 的使用(没有任何编译器错误)可能会导致运行时出现问题(主要与与没有强制可空性的语言的互操作有关):例如将 null 隐式转换为文字字符串 @ 987654327@(与另一个字符串连接时),甚至在传递给接受 String! (platform type) 且未正确注释的方法时出现 NPE。

坚持 DDD 原则,更好的选择是声明单独的数据类型:

sealed class OptionalPhoneNumber
data class PhoneNumber(val value: String) : OptionalPhoneNumber() //You may also add some checks in init block that `value` is really a phone number, not just a set of random chars
object EmptyPhoneNumber : OptionalPhoneNumber()

并将您的数据类定义为:

data class Data (
    val telephone1: PhoneNumber,
    val telephone2: OptionalPhoneNumber
)

类型系统将强制您执行x is PhoneNumber 检查,并且由于智能转换,它的进一步使用将是类型安全的:

if (telephone2 is PhoneNumber) {
    println(telephone2.value)
}

【讨论】:

  • 您说“主要与没有强制可空性的语言的互操作相关”,如果互操作不存在怎么办?它是 Java 和 Kotlin 的混合体;新代码是用 Kotlin 编写的,这个 pojo 只会在新功能中使用。可能存在哪些非互操作问题?
  • 而且,这不是重新发明 null 的例子吗? medium.com/@elizarov/dealing-with-absence-of-value-307b80534903
  • >这不是重新发明 null 的例子吗不,不是。 EmptyPhoneNumber 表示不存在OptionalPhoneNumber,而不是一般不存在某种类型的数据(如Optional<T> 中的nullNone 那样)。例如,如果您以相同的样式定义OptionalAddress,则会有EmptyAddress,与EmptyPhoneNumber 区分开来。
  • >除了提到的隐式转换为“null”字符串之外,可能存在哪些非互操作问题,null 的使用稍微放松了类型系统。这将在没有警告的情况下编译并在运行时工作:val a: PhoneNumber? = null; val b: Address? = a as Address?。这将发出编译器警告 (This cast can never succeed) 和运行时异常:val a = EmptyPhoneNumber; val b: OptionalAddress = (a as OptionalAddress) 这可能不是实际问题,而只是拒绝提供一些额外的保护。
猜你喜欢
  • 2021-03-14
  • 1970-01-01
  • 1970-01-01
  • 2012-07-13
  • 2021-06-06
  • 2021-06-01
  • 2012-10-14
  • 1970-01-01
  • 2014-05-25
相关资源
最近更新 更多