简体   繁体   中英

Spring Data Rest Put not updating with immutable entity on SpringBoot 2.1.x

After updating to the spring boot starter version 2.1.5 put requests don't update the entity anymore with immutable entities.

Put requests work on spring boot starter 2.0.3 but not on 2.1.4 & 2.1.5. Using the Patch method however works fine.

Since I am working in Kotlin my code is written in Kotlin but I can also reproduce this with a Java entity:

Given the entites:

@Entity
data class MyEntityKt(
     @Id
     @GeneratedValue
     val id: UUID? = null,
     @Version
     val version: Long = 0,
     val name: String = "",
     val description: String = ""
)
@Value
@Wither
@Entity
@RequiredArgsConstructor
public class MyEntityJava {

    public MyEntityJava() {
        id = null;
        version = 0;
        name = "";
        description = "";
    }

    @Id
    @GeneratedValue
    private final UUID id;
    @Version
    private final long version;
    private final String name;
    private final String description;
}

And the two corresponding RestRepositories:

@RepositoryRestResource(path = "kotlin")
interface MyEntityRepository : JpaRepository<MyEntityKt, UUID>

@RepositoryRestResource(path = "java")
interface ImmutableEntityRepository : JpaRepository<MyEntityJava, UUID>

And in my test ( @SpringBootTest ) I try the following:

@Test
fun testPut() {
    val myEntity = myEntityRepository.save(MyEntityKt(name = "TestName", description = "TestDescription"))
    val update = this.mockMvc.perform(
        put("/kotlin/${myEntity.id}")
            .accept(MediaType.APPLICATION_JSON_UTF8)
            .contentType(MediaType.APPLICATION_JSON_UTF8)
            .content(
                """
                {
                    "name": "TestNameModified",
                    "description": "TestDescriptionModified"
                }
            """.trimIndent()
            )
    )
    .andReturn().response.contentAsByteArray.let { objectMapper.readValue(it, MyEntityKt::class.java) }

    val updatedEntity = myEntityRepository.findById(myEntity.id!!).get()

    assertThat(updatedEntity.name).isEqualTo("TestNameModified")    
    assertThat(updatedEntity.description).isEqualTo("TestDescriptionModified")
}

Also the response I get is:

{
    "name" : "TestName",
    "description" : "TestDescription",
    "_links" : {
    "self" : {
        "href" : "http://localhost/kotlin/fd83f256-3515-41b0-b9c7-7bfe53a367f8"
    },
    "myEntityKt" : {
        "href" : "http://localhost/kotlin/fd83f256-3515-41b0-b9c7-7bfe53a367f8"
    }
}

I did some investigation and org.springframework.data.rest.webmvc.json.DomainObjectReader.MergingPropertyHandler#doWithPersistentProperty which I guess would be responsible for creating an updated version of my entity to persist, seems like it is only setting the values on the accessor but not actually creating an updated object.

On spring boot version 2.0.3 the test case passes, on 2.1.5 however the entity is not updated, and there is no actual reason given (eg, log output) why the entity is not updated. My guess is that it has something to do with the fact that the entites are immutable but I don`t see why this worked previously.

EDIT: I uploaded the testcase to Github

I found the solution to my problem:

  1. Annotate the entity as Immutable
  2. Make the version and the id property mutable
@Entity
@org.springframework.data.annotation.Immutable
data class MyEntityKt(
     @Id
     @GeneratedValue
     var id: UUID? = null,
     @Version
     var version: Long = 0,
     val name: String = "",
     val description: String = ""
)

The Immutable annotation caused the json response that I was getting to be the correctly updated one but it inserted a new entry into the database with my updated values.

So to make it override the existing entity I had to make the id and the version mutable.

Also in the json I send to update the entity I included the version to work for subsequent updates like this:

{
    "name": "TestNameModified",
    "description": "TestDescriptionModified",
    "version": 0
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM