英文:
How to map from DTO to domain when have nullable field in API and don't need it on domain model
问题
DTO 模型:
@Serializable
data class PrivilegeWidgetDto(
val widgetHeader: String,
val widgetText: String,
val bottomSheet: BottomSheetDto? = null,
)
@Serializable
data class BottomSheetDto(
val bottomSheetText: String? = null,
val bottomSheetHeader: String? = null,
)
领域模型:
@Serializable
data class PrivilegeWidget(
val widgetHeader: String? = null,
val widgetText: String? = null,
val bottomSheet: BottomSheetData? = null,
)
@Serializable
data class BottomSheetData(
// 想要使这些字段非可空
val bottomSheetText: String? = null,
val bottomSheetHeader: String? = null,
)
我使用扩展函数进行映射:
fun PrivilegeWidgetDto.mapToDomain(): PrivilegeWidget {
return PrivilegeWidget(
widgetHeader = this.widgetHeader,
widgetText = this.widgetText,
bottomSheet = BottomSheetData(
bottomSheetHeader = this.bottomSheet?.bottomSheetHeader,
bottomSheetText = this.bottomSheet?.bottomSheetText
)
)
}
问题是,尽管 PrivilegeWidget
中的 bottomSheet
可能为空,但它自己的字段不应该是可空的(如果 bottomSheet
不为空,它总是包含 bottomSheetHeader
和 bottomSheetText
)。否则,我必须使用可空值,尽管我不需要它们。
有没有好的处理方法?如果我像这样做,是否可以解决问题:
bottomSheet = BottomSheetData_(
bottomSheetHeader = this.bottomSheet?.bottomSheetHeader!!,
bottomSheetText = this.bottomSheet?.bottomSheetText!!
)
或者:
bottomSheet = BottomSheetData_(
bottomSheetHeader = this.bottomSheet?.bottomSheetHeader ?: "",
bottomSheetText = this.bottomSheet?.bottomSheetText ?: ""
)
更新:
如果我在 DTO 和领域对象中将 bottomSheetHeader
和 bottomSheetText
定义为非可空,我在映射器中会收到编译器错误,并面临相同的问题:
只允许在类型为 BottomSheetDto? 的可空接收者上进行安全的 (?.) 或非空断言 (!!.) 调用
如果 bottomSheet
是可空的,映射器会将其字段视为可空,即使它们是非可空的。因此,我必须在映射器中解决与可空性相关的相同问题。
英文:
I get a complex model from server with Retrofit. I simplified it to make it more obvious.
Two fields are obligatory, but bottomSheet
is optional. The problem is that I have to make all the fields of domain model BottomSheetData
nullable even though I don't need them nullable.
DTO models:
@Serializable
data class PrivilegeWidgetDto(
val widgetHeader: String,
val widgetText: String,
val bottomSheet: BottomSheetDto? = null,
)
@Serializable
data class BottomSheetDto(
val bottomSheetText: String? = null,
val bottomSheetHeader: String? = null,
)
Domain models:
@Serializable
data class PrivilegeWidget(
val widgetHeader: String? = null,
val widgetText: String? = null,
val bottomSheet: BottomSheetData? = null,
)
@Serializable
data class BottomSheetData(
//want to make these fields not nullable
val bottomSheetText: String? = null,
val bottomSheetHeader: String? = null,
)
I use extension function to map:
fun PrivilegeWidgetDto.mapToDomain() : PrivilegeWidget {
return PrivilegeWidget(
widgetHeader = this.widgetHeader,
widgetText = this.widgetText,
bottomSheet = BottomSheetData(
bottomSheetHeader = this.bottomSheet?.bottomSheetHeader,
bottomSheetText = this.bottomSheet?.bottomSheetText
)
)
}
The problem is that though bottomSheet
in PrivilegeWidget
may be null, its own fields should not be nullable (if bottomSheet != null it always contains bottomSheetHeader
and bottomSheetText
). Otherwise I have to work with nullable values even though I don't need them.
Is these any good practice to handle it? What if I make sth like this - are these solution ok?
bottomSheet = BottomSheetData_(
bottomSheetHeader = this.bottomSheet?.bottomSheetHeader!!,
bottomSheetText = this.bottomSheet?.bottomSheetText!!
)
bottomSheet = BottomSheetData_(
bottomSheetHeader = this.bottomSheet?.bottomSheetHeader ?: "",
bottomSheetText = this.bottomSheet?.bottomSheetText ?: ""
)
UPD:
If I define bottomSheetHeader
and bottomSheetText
as non-nullable in both DTO and Domain objects I get compiler error in mapper and face the same problem:
> Only safe (?.) or non-null asserted (!!.) calls are allowed on a
> nullable receiver of type BottomSheetDto?
If bottomSheet
is nullable mapper treats its fields as nullable too even if they are non-nullable. So I have to solve same problems with nullability in mapper.
答案1
得分: 1
使用BottomSheetData类中的辅助构造函数来强制其字段非空是实现这一目标的一种方法:
data class BottomSheetData(
val bottomSheetText: String,
val bottomSheetHeader: String
) {
constructor(bottomSheetText: String?, bottomSheetHeader: String?) : this(
bottomSheetText ?: "",
bottomSheetHeader ?: ""
)
}
现在,当你创建BottomSheetData的实例时,你可以使用辅助构造函数来处理bottomSheet可为空的情况:
fun PrivilegeWidgetDto.mapToDomain(): PrivilegeWidget {
return PrivilegeWidget(
widgetHeader = this.widgetHeader,
widgetText = this.widgetText,
bottomSheet = this.bottomSheet?.let {
BottomSheetData(
bottomSheetText = it.bottomSheetText,
bottomSheetHeader = it.bottomSheetHeader
)
}
)
}
英文:
One way to achieve this is by using a secondary constructor in the BottomSheetData class to enforce non-nullability of its fields:
data class BottomSheetData(
val bottomSheetText: String,
val bottomSheetHeader: String
) {
constructor(bottomSheetText: String?, bottomSheetHeader: String?) : this(
bottomSheetText ?: "",
bottomSheetHeader ?: ""
)
Now, when you create an instance of BottomSheetData, you can use the secondary constructor to handle the case where bottomSheet is nullable
fun PrivilegeWidgetDto.mapToDomain(): PrivilegeWidget {
return PrivilegeWidget(
widgetHeader = this.widgetHeader,
widgetText = this.widgetText,
bottomSheet = this.bottomSheet?.let {
BottomSheetData(
bottomSheetText = it.bottomSheetText,
bottomSheetHeader = it.bottomSheetHeader
)
}
)
}
答案2
得分: 1
像这样添加两个单独的扩展函数并将 bottomSheetHeader
和 bottomSheetText
更改为非空:
fun PrivilegeWidgetDto.mapToDomain(): PrivilegeWidget {
return PrivilegeWidget(
widgetHeader = this.widgetHeader,
widgetText = this.widgetText,
bottomSheet = bottomSheet?.mapToDomain()
)
}
fun BottomSheetDto.mapToDomain(): BottomSheetData {
return BottomSheetData(
bottomSheetHeader = bottomSheetHeader ?: "",
bottomSheetText = bottomSheetText ?: ""
)
}
编译器报错 只允许在可空接收器类型 BottomSheetDto? 上进行安全 (?.) 或非空断言 (!!.) 调用
,因为在你的扩展函数中 this.bottomSheet
已经是可空的,任何其他操作都需要进行空值检查。
英文:
add 2 separate extension functions like this and change bottomSheetHeader
and bottomSheetText
as non-nullable
fun PrivilegeWidgetDto.mapToDomain() : PrivilegeWidget {
return PrivilegeWidget(
widgetHeader = this.widgetHeader,
widgetText = this.widgetText,
bottomSheet = bottomSheet?.mapToDomain()
)
}
fun BottomSheetDto.mapToDomain(): BottomSheetData {
return BottomSheetData(
bottomSheetHeader = bottomSheetHeader,
bottomSheetText = bottomSheetText
)
}
Compiler complains about Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type BottomSheetDto?
because in your exention function this.bottomSheet
is already nullable and any other operation will require null checks.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论