简体   繁体   中英

Spring JPA doesn't validate bean on update

I'm using Spring Boot 1.5.7, Spring JPA, Hibernate validation, Spring Data REST, Spring HATEOAS.

I've a simple bean like this:

@Entity
public class Person {
    @Id
    @GeneratedValue
    private Long id;

    @NotBlank
    private String name;
}

As you can see I'm using @NotBlank. According to Hibernate documentation the validation should be made on pre-persist and pre-update.

I created a junit test:

@Test(expected = ConstraintViolationException.class)
public void saveWithEmptyNameThrowsException() {  
    Person person = new Person();
    person.setName("");
    personRepository.save(person);
}

this test works fine and therefore the validation process happens correctly. Instead in this test case, the validation doesn't work:

@Test(expected = ConstraintViolationException.class)
public void saveWithEmptyNameThrowsException() {
   Person person = new Person();
   person.setName("Name");
   personRepository.save(person);

   person.setName("");
   personRepository.save(person);
}

I found another similar question but unfortunately there isn't any reply. Why the validation is not made on update() method? Advice to solve the problem?

I think ConstraintViolationException is not occurred because during update Hibernate don't flush result to database on the spot. Try to replace in your test save() with saveAndFlush().

Are you using Spring Boot JPA test? If yes, saveWithEmptyNameThrowsException is wrapped within a transaction, and it will not be committed until the method's execution is done. In other words, the method is treated as one unit of work. Calling personRepository.save (unless you enable auto commit/flush changes) will not resort to reflection of your entity changes, but until transaction is committed. Here's a workaround for your test:

@Test(expected = ConstraintViolationException.class)
public void saveWithEmptyNameThrowsException() {
   // Wrap the following into another transaction
   // begin
      Person person = new Person();
      person.setName("Name");
      personRepository.save(person);
   // commit

   // Wrap the following into another transaction
   // begin
      person = ... get from persistence context
      person.setName("");
      personRepository.save(person);
   // commit
}

You can use TransactionTemplate for programmatic transaction demarcation in Spring.

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