I tried to update one of my Spring Boot/Spring Data R2dbc example project to the latest Spring Boot 3.0.5 stack. In the original Spring Boot 2.7, the Repository tests worked.
The R2dbc entity is like this.
@Table(value = "posts")
data class Post(
@Id
@Column("id")
val id: UUID? = null,
@Column("title")
var title: String,
@Column("content")
var content: String,
@Column("status")
var status: Status = Status.DRAFT,
@Column("created_at")
@CreatedDate
val createdAt: LocalDateTime? = null,
@Column("created_by")
@CreatedBy
val createdBy: String? = null,
@Column("updated_at")
@LastModifiedDate
val updatedAt: LocalDateTime? = null,
@Column("version")
@Version
@JsonIgnore
val version: Long? = null,
)
The repository tests is like this.
@OptIn(ExperimentalCoroutinesApi::class)
@DataR2dbcTest
@Testcontainers
@Import(DataConfig::class)
class PostRepositoryTest {
companion object {
private val log = LoggerFactory.getLogger(PostRepositoryTest::class.java)
@Container
private val postgreSQLContainer: PostgreSQLContainer<*> = PostgreSQLContainer<Nothing>("postgres:12")
@DynamicPropertySource
@JvmStatic
fun registerDynamicProperties(registry: DynamicPropertyRegistry) {
registry.add("spring.r2dbc.url") {
"r2dbc:postgresql://${postgreSQLContainer.host}:${postgreSQLContainer.firstMappedPort}/${postgreSQLContainer.databaseName}"
}
registry.add("spring.r2dbc.username") { postgreSQLContainer.username }
registry.add("spring.r2dbc.password") { postgreSQLContainer.password }
}
}
@Autowired
lateinit var dbclient: DatabaseClient
@Autowired
lateinit var template: R2dbcEntityTemplate
@Autowired
lateinit var posts: PostRepository
@BeforeEach
fun setup() = runTest {
val deleted = template.delete(Post::class.java).all().awaitSingle()
log.debug("clean posts list before tests: $deleted")
}
@Test
fun testDatabaseClientExisted() {
assertNotNull(dbclient)
}
@Test
fun testR2dbcEntityTemplateExisted() {
assertNotNull(template)
}
@Test
fun testPostRepositoryExisted() {
assertNotNull(posts)
}
@Test
fun testInsertAndQuery() = runTest {
val data = Post(title = "test title", content = "test content")
val saved = posts.save(data)
// verify id is inserted.
assertNotNull(saved.id)
val existed = posts.findById(saved.id!!)!!
log.debug("found existed post: $existed")
//verify the saved data
assertThat(existed.title).isEqualTo("test title")
assertThat(existed.status).isEqualTo(Status.DRAFT)
existed.apply {
title = "update title"
status = Status.PENDING_MODERATION
}
posts.save(existed) // this line caused failure
val updatedPosts = posts.findByTitleContains("update")
//verify the updated title
assertThat(updatedPosts.count()).isEqualTo(1)
assertThat(updatedPosts.toList()[0].title).isEqualTo("update title")
}
...
}
I got the following exceptions:
2023-04-15T12:18:33.376+08:00 DEBUG 8320 --- [in @coroutine#2] com.example.demo.PostRepositoryTest :
found existed post: Post(id=1ba70b74-8de6-4200-8953-40f180a08c8b, title=test title, content=test content, status=DRAFT, createdAt=2023-04-15T12:18:33.213805, createdBy=null, updatedAt=2023-04-15T12:18:33.213805, version=0)
2023-04-15T12:18:33.528+08:00 DEBUG 8320 --- [in @coroutine#2] o.s.r2dbc.core.DefaultDatabaseClient :
Executing SQL statement [UPDATE posts SET title = $1, content = $2, status = $3, created_at = $4, created_by = $5, updated_at = $6, version = $7 WHERE posts.id = $8 AND (posts.version = $9)]
2023-04-15T12:18:33.607+08:00 DEBUG 8320 --- [in @coroutine#2] o.s.r2dbc.core.DefaultDatabaseClient :
Executing SQL statement [SELECT posts.id, posts.title FROM posts WHERE posts.title LIKE $1]
org.springframework.data.mapping.model.MappingInstantiationException:
Failed to instantiate com.example.demo.domain.model.Post
using constructor fun <init>(java.util.UUID?, kotlin.String, kotlin.String, com.example.demo.domain.model.Status, java.time.LocalDateTime?, kotlin.String?, java.time.LocalDateTime?, kotlin.Long?):
com.example.demo.domain.model.Post with arguments
1ba70b74-8de6-4200-8953-40f180a08c8b,update title,null,null,null,null,null,null,248,null
at org.springframework.data.mapping.model.
KotlinClassGeneratingEntityInstantiator$DefaultingKotlinClassInstantiatorAdapter.createInstance
I am not sure why it is trying to instantiate an entity when updating the existed entity? In the test, I just want to update the title and status field, not to update the content field, which caused this exception.
When changing the content to nullable, the test is passed. But I think it is unreasonable.
Your analysis isn't correct. The update statement passes, and the statement later on SELECT posts.id, posts.title FROM posts doesn't select the content column; Therefore, you cannot instantiate the object.
I tried to update one of my Spring Boot/Spring Data R2dbc example project to the latest Spring Boot 3.0.5 stack. In the original Spring Boot 2.7, the Repository tests worked.
The R2dbc entity is like this.
The repository tests is like this.
I got the following exceptions:
I am not sure why it is trying to instantiate an entity when updating the existed entity? In the test, I just want to update the title and status field, not to update the content field, which caused this exception.
When changing the
content
to nullable, the test is passed. But I think it is unreasonable.