51

I have a spring boot project that has a CrudRepository, an Entity and a Controller. I am basically trying to persist an entity based on the data passed to the Controller.

To do this, I am using spring-boot-starter-jpa. My Entity is annotated with JSR-303 annotations, which are checked in the controller before the data gets passed to the CrudRepository for persistence.

Controller method:

@RequestMapping(value = "users", method = { RequestMethod.POST })
public SuccessfulResponse<User> addUser(@Valid @RequestBody User user, BindingResult validation) {
    if (validation.hasErrors()) {
        throw new ValidationException(validation);
    }
    User saved = this.users.save(user);
    return new SuccessfulResponse<User>(saved);
}

Entity:

@Entity /* JPA */
public class User {

   @Id /* JPA */
   @Column(name="email_address", nullable=false, length=255) /* JPA */
   @UserUnique
   private String emailAddress;

}

The cause of my issues is the UserUnique annotation. Its validator looks like this:

public class UserUniqueValidator implements ConstraintValidator<UserUnique, String> {

   private UserRepository users;

   @Autowired
   public UserUniqueValidator(UserRepository users) {
       this.users = users;
   }

   @Override
   public void initialize(UserUnique annotation) {}

   @Override
   public boolean isValid(String value, ConstraintValidatorContext context) {
       return users.findOne(value) == null;
   }
}

What seems to be happening is, the validation is getting run twice. Once in the controller via the @Valid annotation, and once when Hibernate tries to persist the object. However, when Hibernate tries to persist the object, it throws:

javax.validation.ValidationException: HV000064: Unable to instantiate ConstraintValidator: class test.UserUniqueValidator`

This seems to be because its not spring-aware and cant inject the dependency into the constructor. So, what I want to do is disable Hibernate validation completely (as its redundant and already happening in the controller).

There seems to be a property called javax.persistence.validation.mode which you can set to none. However, I cant for the life of me figure out where to set it in a code-based configuration.

I realise there are questions like JSR-303 dependency injection and Hibernate but these are all using xml config and manually configuring parts of the persistence layer.

What I want to do is "post-configure" the required parts of the persistence layer that Spring Boot creates for me because if I define my own then I am no longer leveraging Spring Boot's auto configuration. Can anyone help me determine if 1) this is possible and 2) which parts do I need to configure and how?

Thanks!

Community
  • 1
  • 1
Erin Drummond
  • 5,347
  • 6
  • 35
  • 41
  • 16
    Add a property to the `application.properties` file. `spring.jpa.properties.javax.persistence.validation.mode=none` should do the trick. – M. Deinum Nov 06 '14 at 07:00
  • Worked perfectly, thanks. Is that mentioned in any spring documentation? – Erin Drummond Nov 07 '14 at 20:04
  • How to set additional JPA properties is explained in the reference guide. – M. Deinum Nov 09 '14 at 15:01
  • Oh right, so it is. I missed it because the example appeared to be Hibernate-specific rather than JPA generic, I should have read the paragraphs under the example more carefully. – Erin Drummond Nov 09 '14 at 19:55
  • Just for reference you don't actually need to handle the object being invalid in your controller. If you remove the BindingResult param spring will already throw an MethodArgumentNotValidException by itself. which you can handle nicely in a @ControllerAdvice with an @ExceptionHandler(MethodArgumentNotValidException) method. – Robbert Jul 11 '16 at 14:09

4 Answers4

54

As [M. Deinum] mentioned in a comment on my original post, the solution is to set:

spring.jpa.properties.javax.persistence.validation.mode=none

In the application.properties file.

Additionally, this behaviour is described here (its easy to miss because no example is provided).

Erin Drummond
  • 5,347
  • 6
  • 35
  • 41
2

@Erin Drummond's Answer is for database entity validation (individual records)

But if someone ran into a problem with schema validation below property works well.

# Hibernate ddl auto (create, create-drop, validate, update, none)
spring.jpa.hibernate.ddl-auto=none
Asad Shakeel
  • 1,949
  • 1
  • 23
  • 29
  • 2
    This has to do with whether or not Hibernate will attempt to run DDL statements on your database to create its structure - it has nothing to do with validation... – Erin Drummond Oct 22 '19 at 16:03
  • here if I use the `validate` option it will compare my Entities with DB tables schema – Asad Shakeel Oct 23 '19 at 09:28
  • 1
    Yes and that is not the kind of validation that this question addresses. This question is talking about database *entity* validation (individual records) - not *schema* validation. – Erin Drummond Oct 23 '19 at 17:49
  • 1
    My bad!! didn't understand the question carefully. Anyhow, will edit the answer. – Asad Shakeel Oct 24 '19 at 08:15
1

Actually, in spring boot 2.x. it is:

spring.jpa.hibernate.ddl-auto: none
ilke444
  • 2,641
  • 1
  • 17
  • 31
John
  • 91
  • 1
  • 1
  • 3
    `spring.jpa.hibernate.ddl-auto` [relates to](https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html#common-application-properties) `hibernate.hbm2ddl.auto` which is to do with automatic schema generation, but the question here is related to validating entities. – Theozaurus Aug 27 '20 at 10:43
-2

for spring boot unless you add validation dependency the spring validation would not kick in.

 <dependency> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-validation</artifactId> 
</dependency>
mohsen
  • 7