Kotlin Code below works fine
private inline fun <reified T> parseResponse(response: Any): Response<T> =
when (response) {
is T -> { Response(success = response, error = null) }
is GetUserInfoResponseResult.Error -> {
Response(
success = null,
error = Error(response.error.message ?: "", response.error.code?.name ?: "")
)
}
is SetUserInfoResponseResult.Error -> {
Response(
success = null,
error = Error(response.error.message ?: "", response.error.code?.name ?: "")
)
}
else -> throw exception("Failed to process response ")
}
However when I try to combine 2 when clauses
private inline fun <reified T> parseResponse(response: Any): Response<T> =
when (response) {
is T -> { Response(success = response, error = null) }
is GetUserInfoResponseResult.Error, SetUserInfoResponseResult.Error -> {
Response(
success = null,
error = Error(response.error.message ?: "", response.error.code?.name ?: "")
)
}
else -> throw exception("Failed to process response ")
}
In intelliJ I got a red underline for Error
in SetuUserInfoResponseResult.Error
saying
classifier Error does not have a companion object and thus must be initialized here
definitions
sealed class GetUserInfoResponseResult {
data class Error(val error: GetUserInfoErrorResponse) : GetUserInfoResponseResult()
data class Success(val success: GetUserInfoSuccessResponse) : GetUserInfoResponseResult()
}
sealed class SetUserInfoResponseResult {
data class Error(val error: SetUserInfoErrorResponse) : SetUserInfoResponseResult()
object Success : SetUserInfoResponseResult()
}
CodePudding user response:
Your current when
clause checks whether response
is an instance of GetUserInfoResponseResult.Error
, or response
is equal to the companion object of SetUserInfoResponseResult.Error
. The second half is an equality check, because you didn't write is
before it. SetUserInfoResponseResult.Error
does not have a companion object, hence the error.
Adding the is
doesn't fix everything. There are still errors where you try to access response.error.message
. This is because smart casts only works when you are checking for a single type. Since you are checking for 2, the compile-time type of response
is not smart casted, and is still Any
.
You can fix this by introducing a common interface that both error types implements:
interface UserInfoErrorResponseResult {
val error: UserInfoErrorResponse
}
interface UserInfoErrorResponse {
val message: String?
val code: ErrorCode? // I assume you have an ErrorCode class like this
}
Then you can just check for one type - is UserInfoErrorResponseResult
- and smart cast would work:
private inline fun <reified T> parseResponse(response: Any): Response<T> =
when (response) {
is T -> { Response(success = response, error = null) }
is UserInfoErrorResponseResult -> {
Response(
success = null,
error = Error(response.error.message ?: "", response.error.code?.name ?: "")
)
}
else -> throw exception("Failed to process response ")
}
Here's an example of how your classes would look like, implementing those interfaces, with some assumptions of how GetUserInfoErrorResponse
and SetUserInfoErrorResponse
look like.
data class GetUserInfoErrorResponse(
override val message: String?,
override val code: ErrorCode?
): UserInfoErrorResponse
data class SetUserInfoErrorResponse(
override val message: String?,
override val code: ErrorCode?
): UserInfoErrorResponse
sealed class GetUserInfoResponseResult {
data class Error(override val error: GetUserInfoErrorResponse) :
GetUserInfoResponseResult(), UserInfoErrorResponseResult
data class Success(val success: GetUserInfoSuccessResponse) : GetUserInfoResponseResult()
}
sealed class SetUserInfoResponseResult {
data class Error(override val error: SetUserInfoErrorResponse) :
SetUserInfoResponseResult(), UserInfoErrorResponseResult
object Success : SetUserInfoResponseResult()
}
Basically, you should just add override
to everything the interface needs, and it should work.