Skip to content

Regarding the issue of MappingInstantiationException caused by using r2dbcEntityTemplate in Kotlin, and the support for Unsigned types by CustomConverter. #1908

Open
@yeyonggui

Description

@yeyonggui
package com.example.demo

import kotlinx.coroutines.flow.toList
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.convert.converter.Converter
import org.springframework.data.annotation.Id
import org.springframework.data.convert.ReadingConverter
import org.springframework.data.r2dbc.convert.R2dbcCustomConversions
import org.springframework.data.r2dbc.core.*
import org.springframework.data.r2dbc.dialect.MySqlDialect
import org.springframework.data.relational.core.mapping.Column
import org.springframework.data.relational.core.mapping.Table
import org.springframework.stereotype.Component
import org.springframework.web.reactive.function.server.ServerResponse
import org.springframework.web.reactive.function.server.bodyValueAndAwait
import org.springframework.web.reactive.function.server.coRouter
import org.springframework.web.reactive.function.server.json


@SpringBootApplication
class Demo1Application

fun main(args: Array<String>) {
    runApplication<Demo1Application>(*args)
}

@Component
class TestController {
    @Bean
    fun testRouter(
        r2dbcEntityTemplate: R2dbcEntityTemplate
    ) = coRouter {
        GET("read") {
            val result = r2dbcEntityTemplate.select<Simple>().flow().toList()
            ServerResponse.ok().json().bodyValueAndAwait(result)
        }
    }
}




@Table(name = "customer")
data class Simple(
    @Id
    @Column("id")
    val id: UInt,
    @Column("name")
    val name: String,
    @Column("age")
    val age: UInt,
)

@Table(name = "customer")
data class PrivateConstructor private constructor(
    @Id
    @Column("id")
    val id: UInt,
    @Column("name")
    val name: String,
    @Column("age")
    val age: UInt,
)

@Table(name = "customer")
data class DefaultId private constructor(
    @Id
    @Column("id")
    val id: UInt=0u,
    @Column("name")
    val name: String,
    @Column("age")
    val age: UInt,
)

@ReadingConverter
object LongToUInt : Converter<Long, UInt> {
    override fun convert(source: Long): UInt {
        println("LongToUInt $source")
        return source.toUInt()
    }
}
@ReadingConverter
object LongToInt : Converter<Long, Int> {
    override fun convert(source: Long): Int {
        println("LongToInt $source")
        return source.toInt()
    }
}
@Configuration
class Config{
    @Bean
    fun customConversions(): R2dbcCustomConversions =
        R2dbcCustomConversions.of(MySqlDialect.INSTANCE, listOf(LongToUInt,LongToInt))
}
CREATE TABLE `customer` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8mb4_general_ci NOT NULL,
  `age` int unsigned DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=55 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

mysql 8.0.24
kotlin 2.0.20
spring-boot 3.3.3

1.When using r2dbcEntityTemplate to query the database, if the Entity constructor is public, everything runs normally regardless of whether the attribute corresponding to the primary Key has a default value. But when the Entity of the constructor is private, if primary key corresponding attributes don't declare a default value, will lead to MappingInstantiationException.

2.Hope ReadingConverter, WriteConverter can support kotlin unsigned type, code only LongToInt will work, but LongToUInt will not.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions