oharaandrew314 / dynamodb-kotlin-module

Kotlin Module for the dynamodb-enhanced SDk
Apache License 2.0
23 stars 3 forks source link

Adding a custom converter to a data class property still makes additional converters for properties of the inner type necessary. #17

Closed PoisonedYouth closed 6 months ago

PoisonedYouth commented 6 months ago

I have the following requirement which is currently not working as expected.

There is a CustomDataClass that has the property of a custom type Subtyp for which a converter exists. Inside the Subtyp there is a property of the Map<String, Any> type. Even if there is a converter for the Subtyp class that is handling the transformation it is necessary to add an additional converter to the Map<String, Any> property in order to make the database creation call successfully.

See below test case for the described problem:

    @Autowired private val enhancedAsyncClient: DynamoDbEnhancedAsyncClient,
) {

    data class Subtyp(
        val map: Map<String, Any>
    )

    class SubtypeConverter: AttributeConverter<Subtyp>{
        override fun transformFrom(input: Subtyp?): AttributeValue {
            TODO("Not yet implemented")
        }

        override fun transformTo(input: AttributeValue?): Subtyp {
            TODO("Not yet implemented")
        }

        override fun type(): EnhancedType<Subtyp> {
            TODO("Not yet implemented")
        }

        override fun attributeValueType(): AttributeValueType {
            TODO("Not yet implemented")
        }

    }

    @DynamoDbBean
    data class CustomDataClass(
        @DynamoKtPartitionKey
        val id: String,
        @DynamoKtConverted(SubtypeConverter::class)
        val subtyp: Subtyp
    )

    @Test
    fun `properties of Subtyp for which a converter exist should not be scanned for a converter` () = runBlockingJUnit{

        enhancedAsyncClient
            .table(UUID.randomUUID().toString(), DataClassTableSchema(CustomDataClass::class))
            .also { it.createTable().await() }

        // This leads to
        //        java.lang.IndexOutOfBoundsException: Index: 0
        //        at java.base/java.util.Collections$EmptyList.get(Collections.java:4586)
        //        at software.amazon.awssdk.enhanced.dynamodb.DefaultAttributeConverterProvider.createMapConverter(DefaultAttributeConverterProvider.java:191)
        //        at software.amazon.awssdk.enhanced.dynamodb.DefaultAttributeConverterProvider.findConverterInternal(DefaultAttributeConverterProvider.java:161)
        //        at software.amazon.awssdk.enhanced.dynamodb.DefaultAttributeConverterProvider.findConverter(DefaultAttributeConverterProvider.java:145)
        //        at software.amazon.awssdk.enhanced.dynamodb.DefaultAttributeConverterProvider.createMapConverter(DefaultAttributeConverterProvider.java:195)
        //        at software.amazon.awssdk.enhanced.dynamodb.DefaultAttributeConverterProvider.findConverterInternal(DefaultAttributeConverterProvider.java:161)
        //        at software.amazon.awssdk.enhanced.dynamodb.DefaultAttributeConverterProvider.findConverter(DefaultAttributeConverterProvider.java:145)
        //        at software.amazon.awssdk.enhanced.dynamodb.DefaultAttributeConverterProvider.converterFor(DefaultAttributeConverterProvider.java:137)
        //        at io.andrewohara.dynamokt.ImmutableDataClassAttributeKt.toImmutableDataClassAttribute(ImmutableDataClassAttribute.kt:86)
        //        at io.andrewohara.dynamokt.DataClassTableSchemaKt.dataClassTableSchema(DataClassTableSchema.kt:43)
        //        at io.andrewohara.dynamokt.DataClassTableSchemaKt.recursiveDataClassTableSchema(DataClassTableSchema.kt:60)
        //        at io.andrewohara.dynamokt.ImmutableDataClassAttributeKt.toEnhancedType(ImmutableDataClassAttribute.kt:35)
        //        at io.andrewohara.dynamokt.ImmutableDataClassAttributeKt.toImmutableDataClassAttribute(ImmutableDataClassAttribute.kt:94)
        //        at io.andrewohara.dynamokt.DataClassTableSchemaKt.dataClassTableSchema(DataClassTableSchema.kt:43)
        //        at io.andrewohara.dynamokt.DataClassTableSchemaKt$DataClassTableSchema$1.invoke(DataClassTableSchema.kt:18)
        //        at io.andrewohara.dynamokt.DataClassTableSchemaKt$DataClassTableSchema$1.invoke(DataClassTableSchema.kt:17)
        //        at io.andrewohara.dynamokt.DataClassTableSchemaKt.DataClassTableSchema$lambda$0(DataClassTableSchema.kt:17)
        //        at java.base/java.util.Map.computeIfAbsent(Map.java:1054)
    }

Is it possible to stop scanning for inner data types if the outer one already contains a converter?

oharaandrew314 commented 6 months ago

If I understand the problem correctly, I think I should be able to correct the behaviour.

On Thu, Feb 29, 2024, 6:27 a.m. Matthias Schenk @.***> wrote:

I have the following requirement which is currently not working as expected.

There is a CustomDataClass that has the property of a custom type Subtyp for which a converter exists. Inside the Subtyp there is a property of the Map<String, Any> type. Even if there is a converter for the Subtyp class that is handling the transformation it is necessary to add an additional converter to the Map<String, Any> property in order to make the database creation call successfully.

See below test case for the described problem:

@Autowired private val enhancedAsyncClient: DynamoDbEnhancedAsyncClient,

) {

data class Subtyp(
    val map: Map<String, Any>
)

class SubtypeConverter: AttributeConverter<Subtyp>{
    override fun transformFrom(input: Subtyp?): AttributeValue {
        TODO("Not yet implemented")
    }

    override fun transformTo(input: AttributeValue?): Subtyp {
        TODO("Not yet implemented")
    }

    override fun type(): EnhancedType<Subtyp> {
        TODO("Not yet implemented")
    }

    override fun attributeValueType(): AttributeValueType {
        TODO("Not yet implemented")
    }

}

@DynamoDbBean
data class CustomDataClass(
    @DynamoKtPartitionKey
    val id: String,
    @DynamoKtConverted(SubtypeConverter::class)
    val subtyp: Subtyp
)

@Test
fun `properties of Subtyp for which a converter exist should not be scanned for a converter` () = runBlockingJUnit{

    enhancedAsyncClient
        .table(UUID.randomUUID().toString(), DataClassTableSchema(CustomDataClass::class))
        .also { it.createTable().await() }

    // This leads to
    //        java.lang.IndexOutOfBoundsException: Index: 0
    //        at java.base/java.util.Collections$EmptyList.get(Collections.java:4586)
    //        at software.amazon.awssdk.enhanced.dynamodb.DefaultAttributeConverterProvider.createMapConverter(DefaultAttributeConverterProvider.java:191)
    //        at software.amazon.awssdk.enhanced.dynamodb.DefaultAttributeConverterProvider.findConverterInternal(DefaultAttributeConverterProvider.java:161)
    //        at software.amazon.awssdk.enhanced.dynamodb.DefaultAttributeConverterProvider.findConverter(DefaultAttributeConverterProvider.java:145)
    //        at software.amazon.awssdk.enhanced.dynamodb.DefaultAttributeConverterProvider.createMapConverter(DefaultAttributeConverterProvider.java:195)
    //        at software.amazon.awssdk.enhanced.dynamodb.DefaultAttributeConverterProvider.findConverterInternal(DefaultAttributeConverterProvider.java:161)
    //        at software.amazon.awssdk.enhanced.dynamodb.DefaultAttributeConverterProvider.findConverter(DefaultAttributeConverterProvider.java:145)
    //        at software.amazon.awssdk.enhanced.dynamodb.DefaultAttributeConverterProvider.converterFor(DefaultAttributeConverterProvider.java:137)
    //        at io.andrewohara.dynamokt.ImmutableDataClassAttributeKt.toImmutableDataClassAttribute(ImmutableDataClassAttribute.kt:86)
    //        at io.andrewohara.dynamokt.DataClassTableSchemaKt.dataClassTableSchema(DataClassTableSchema.kt:43)
    //        at io.andrewohara.dynamokt.DataClassTableSchemaKt.recursiveDataClassTableSchema(DataClassTableSchema.kt:60)
    //        at io.andrewohara.dynamokt.ImmutableDataClassAttributeKt.toEnhancedType(ImmutableDataClassAttribute.kt:35)
    //        at io.andrewohara.dynamokt.ImmutableDataClassAttributeKt.toImmutableDataClassAttribute(ImmutableDataClassAttribute.kt:94)
    //        at io.andrewohara.dynamokt.DataClassTableSchemaKt.dataClassTableSchema(DataClassTableSchema.kt:43)
    //        at io.andrewohara.dynamokt.DataClassTableSchemaKt$DataClassTableSchema$1.invoke(DataClassTableSchema.kt:18)
    //        at io.andrewohara.dynamokt.DataClassTableSchemaKt$DataClassTableSchema$1.invoke(DataClassTableSchema.kt:17)
    //        at io.andrewohara.dynamokt.DataClassTableSchemaKt.DataClassTableSchema$lambda$0(DataClassTableSchema.kt:17)
    //        at java.base/java.util.Map.computeIfAbsent(Map.java:1054)
}

Is it possible to stop scanning for inner data types if the outer one already contains a converter?

— Reply to this email directly, view it on GitHub https://github.com/oharaandrew314/dynamodb-kotlin-module/issues/17, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAG2JSEZF4WWJLFGGOY7POLYV4IATAVCNFSM6AAAAABD7XQBYGVHI2DSMVQWIX3LMV43ASLTON2WKOZSGE3DCMBTGIYTKMA . You are receiving this because you are subscribed to this thread.Message ID: @.***>

PoisonedYouth commented 6 months ago

That would be perfectly. In our productive application there are a lot of nested cases and it's for the reader some kind of weird to have an annotation on a property (also providing custom converter for this) but it does not have an effect.

oharaandrew314 commented 6 months ago

A fix has been released as 0.8.1. The associated test is here.

PoisonedYouth commented 6 months ago

It is working fine. Perfect. Thanks :-)