У меня есть класс данных, скажем, Person, который определяет данные бизнес-логики человека в приложении.
Код: Выделить всё
import kotlinx.serialization.Serializable
data class Person(
val id: String,
val name: String,
val age: Int,
val currentEmployment: Employment,
val workPermit: WorkPermit
)
@Serializable
data class Employment(
val employer: String,
val job: String,
val yearsWithEmployer: Double
)
@Serializable
data class WorkPermit(
val nationality: String,
val visa: String
)
По нескольким причинам я решил реализовать класс DAO, который по сути является копией класса Person, называемого PersonRecord, за исключением того, что поля, содержащие сложные типы, то есть Employment и WorkPermit, вместо этого хранятся как строки. Кроме того, все поля являются изменяемыми и допускают значение NULL. Мне пришлось сделать это таким образом, потому что это должен был быть класс сопоставления для расширенного клиента DynamoDB (doc).
Аннотация этого класса как @DynamoDbBean определяет, как клиент записывает элементы в указанную таблицу.
Код: Выделить всё
package util
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable
import software.amazon.awssdk.enhanced.dynamodb.Key
import software.amazon.awssdk.enhanced.dynamodb.TableSchema
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSortKey
@DynamoDbBean
internal data class PersonRecord(
@get: DynamoDbPartitionKey
@get: DynamoDbSortKey
var id: String? = null,
var name: String? = null,
var age: Int? = null,
var currentEmployment: String? = null,
var workPermit: String? = null,
)
class PersonDao(
ddb: DynamoDbEnhancedClient,
personTableName: String
) {
private val personTable: DynamoDbTable
= ddb.table(
personTableName,
TableSchema.fromBean(PersonRecord::class.java)
)
private fun toPersonRecord(person: Person): PersonRecord =
PersonRecord(
id = person.id,
name = person.name,
age = person.age,
currentEmployment = Json.encodeToString(person.currentEmployment),
workPermit = Json.encodeToString(person.workPermit)
)
private fun toPerson(personRecord: PersonRecord): Person =
Person(
id = personRecord.id!!,
name = personRecord.name!!,
age = personRecord.age!!,
currentEmployment = Json.decodeFromString(
personRecord.currentEmployment!!
),
workPermit = Json.decodeFromString(
personRecord.workPermit!!
)
)
fun writePerson(person: Person) =
personTable.putItem(toPersonRecord(person))
fun readPerson(id: String): Person? {
val personRecord = personTable.getItem(
Key.builder()
.partitionValue(id)
.build()
)
return if (personRecord != null) toPerson(personRecord)
else null
}
}
Есть ли способ более элегантного копирования между различными классами Person и PersonRecord? Если в будущем мы немного изменим форму Person, многое изменится и в классах PersonRecord и PersonDao. В частности, мне нужен способ декодирования String в Employment и WorkPermit и наоборот.
В приведенном выше примере было бы просто добавить одно или два поля, но в моем реальном приложении я имею дело с более чем дюжиной полей и кучей модульных тестов, запутанно связанных с самими полями.
Кто-то предложил использовать отражения классов, но я не понимаю, как бы я его использовал, основываясь на том, что описано в документации Kotlin.
Подробнее здесь: https://stackoverflow.com/questions/737 ... ther-class
Мобильная версия