HeterogeneousItemConverter

class HeterogeneousItemConverter<T>(val typeMapper: (T) -> String, val typeAttribute: String, val subConverters: Map<String, ItemConverter<T>>) : Converter<T, Item>

An item converter which handles heterogeneous (i.e., incongruent) data types by way of a string discriminator attribute identified by typeAttribute. The given typeMapper function must return a string type name for an object which will be used for the typeAttribute attribute. Finally, the given subConverters map identifies the delegate converters for each type.

This converter is particularly (although not solely) useful for mapping polymorphic structures. For example, given a class hierarchy:

sealed interface Vehicle

@DynamoDbItem
data class Car(
@DynamoDbPartitionKey val id: Int,
val manufacturer: String,
val model: String,
val year: Int,
) : Vehicle

@DynamoDbItem
data class Bike(
@DynamoDbPartitionKey val id: Int,
val manufacturer: String
val gears: Int,
val isElectric: Boolean,
) : Vehicle

A heterogeneous item converter can be constructed:

fun vehicleType(obj: Vehicle) = when (obj) {
is Car -> "car"
is Bike -> "bike"
}

val vehicleConverter = HeterogeneousItemConverter(
typeMapper = ::vehicleType,
typeAttribute = "type",
subConverters = mapOf(
"car" to CarConverter,
"bike" to BikeConverter,
),
)

Objects mapped in this manner will use only the attributes relevant to their specific type, plus the typeAttribute. For example, given the following items and PutItem calls:

val vehicles = listOf(
Car(1, "Ford", "Model T", 1928),
Bike(2, "Schwinn", 10, false),
Car(3, "Edsel", "Corsair", 1958),
Bike(4, "Kuwahara", 1, false),
)

val table = ... // some table which uses the vehicleConverter from above in its schema

vehicles.forEach { vehicle ->
table.putItem(vehicle)
}

Items would be persisted in the table as:

idtypemanufacturermodelyeargearsisElectric
1carFordModel T1928
2bikeSchwinn10false
3carEdselCorsair1958
4bikeKuwahara1false

Parameters

typeMapper

A function which accepts an instance of the common type T and returns the string identifier for the type. This identifier is written/read from the attribute identified by typeAttribute and used as a lookup key in subConverters.

typeAttribute

The name of the attribute in which to store/read type information. This attribute will be present for every item persisted via this converter. It should ideally be an attribute which doesn't conflict with other attributes used by subconverters.

subConverters

A map of type names (the same returned by typeMapper) to ItemConverter instances. If the typeMapper function returns a type name which does not exist in this map, or if an item is read containing a type attribute value which does not exist in this map, an exception will be thrown.

Type Parameters

T

The common type ancestor for all subtypes handled by this converter. This may be a base class, interface, or even Any.

Constructors

Link copied to clipboard
constructor(typeMapper: (T) -> String, typeAttribute: String, subConverters: Map<String, ItemConverter<T>>)

Properties

Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
val typeMapper: (T) -> String

Functions

Link copied to clipboard
open override fun convertLeft(from: Item): T
Link copied to clipboard
open override fun convertRight(from: T): Item

Inherited functions

Link copied to clipboard
fun <V : Any> ValueConverter<V>.asNullable(nullValueConverter: ValueConverter<Nothing?> = NullValueConverter): ValueConverter<V?>
Link copied to clipboard
fun <T, PK : KeyType> ItemConverter<T>.withKeySpec(partitionKey: KeySpec<PK>, attributes: Attributes = emptyAttributes()): ItemSchema.PartitionKey<T, PK>

Associate this ItemConverter with a KeySpec for a partition key to form a complete ItemSchema

fun <T, PK : KeyType, SK : KeyType> ItemConverter<T>.withKeySpec(partitionKey: KeySpec<PK>, sortKey: KeySpec<SK>, attributes: Attributes = emptyAttributes()): ItemSchema.CompositeKey<T, PK, SK>

Associate this ItemConverter with KeySpec instances for a composite key to form a complete ItemSchema