клиент может запросить сервер таким образом (доступны только 3 типа значений, а длина может быть больше 3)
{
data = [
{
"id": 1,
"value": "string"
},
{
"id": 2,
"value": {
"address" : "1",
"next" : "3",
}
},
{
"id": 3,
"value": {
"count" : "1",
"option" : "3",
}
},
и я хочу сгруппировать 3 вида типов значений строка / { "количество", "опция"} / {"адрес", "далее"}
data class Request(
val data: SealedLikeClass,
)
как я могу определить SealedLikeClass
?
Я не знаю, как включить строку в запечатанный класс
оба !!!!!!!!!!
Вы можете определить закрытую иерархию классов с помощью универсального Request<T>
. Это ограничит параметр типа T
точно из 3 упомянутых вами форм. Вы можете снять это ограничение, удалив ключевое слово sealed
.
Так:
sealed interface Request<T> {
val id: Int
val value: T
}
data class StringRequest(
override val id: Int,
override val value: String
) : Request<String>
data class Count(val count: String, val option: String)
data class CountRequest(
override val id: Int,
override val value: Count
) : Request<Count>
data class Address(val address: String, val next: String)
data class AddressRequest(
override val id: Int,
override val value: Address
) : Request<Address>
На самом деле, если вам не нужно sealed
-ограничение, вам не нужны и другие Request
-классы. В этом случае вы можете просто сделать это:
data class Request<T>(val id: Int, val value: T)
val aStringRequest = Request(5, "string")
data class Count(val count: String, val option: String)
val aCountRequest = Request(5, Count("count", "option"))
data class Address(val address: String, val next: String)
val anAddressRequest = Request(5, Address("address", "next"))
Изменить после комментария от OP:
Если вы хотите, чтобы только значение было запечатанным типом, вы не можете поддерживать случай, когда значение является строкой, потому что вы не можете заставить String
расширить свой собственный пользовательский интерфейс. Если вы откажетесь от этого случая, вы можете сделать это:
data class Request(val key: String, val value: RequestValue)
sealed interface RequestValue
data class Count(val count: String, val option: String) : RequestValue
data class Address(val address: String, val next: String) : RequestValue
Я предполагаю, что подклассы Request
были бы необходимы, если бы целью была десериализация JSON из сетевых ответов.
Вероятно, модификатор sealed
также понадобится, если OP не хочет прыгать через обручи, чтобы определить полиморфную десериализацию. По крайней мере, в kotlinx.serialization
модификатора sealed
может быть достаточно IIRC, но без sealed
подклассы должны быть зарегистрированы вручную (или явно упомянуты на сайте вызова десериализации, но это не всегда возможно)
Я хочу создать один класс DTO ``` класса данных RequestDto (ключ val: String, значение val: CommonClass) ```, но можно создать экземпляр запечатанного... возможно ли сгруппировать в CommonClass?
Я обновил вопрос, кто-нибудь поможет?
@ReallyJoey Это невозможно из-за первого примера, где значение представляет собой просто строку. Вы не можете изменить суперкласс String
на CommonClass
.
@marstran Что делать, если строка игнорируется? Я имею в виду, что существуют только количество и адрес
В настоящее время вы не можете определить запечатанный класс с существующими примитивными типами. Это потребовало бы объединения, но в настоящее время они не обозначаются в Котлине (см. https://youtrack.jetbrains.com/issue/KT-13108/Denotable-union-and-intersection-types).
В вашем случае похоже, что возможные типы для value
не связаны и на самом деле не связаны друг с другом. В этом случае лучше всего, вероятно, использовать подход, основанный на дженериках , предложенный @marstran выше . Это полезно и хорошо работает, если вы уже знаете нужный вам подтип Request
на сайте вызова.
Другой подход, по крайней мере, с использованием Kotlinx Serialization, заключается в том, чтобы определить тип как JsonElement
, а затем отложить десериализацию на более позднее время (если вы только позже узнаете тип тела запроса).
Теперь, если свойство value
представляет что-то конкретное, что может иметь разные формы (в отличие от общего и представления любого несвязанного типа тела запроса), вы можете определить свой собственный запечатанный класс для этого типа в Kotlin (возможно, с оболочкой для строки версия или что-то лучше), а затем добавьте собственный десериализатор JSON для вашего типа, который также может работать с простыми строками.
Вы пытаетесь сериализовать и десериализовать этот JSON? Или оба?