title: @unique constraint with database support in hibernate
body: <p>I have a spring project and want to enforce uniqueness in the database on a field and get the error message back to the UI.</p>
  
  <p>I have read <a href="https://stackoverflow.com/questions/4546131/using-unique-constraint-on-hibernate-jpa2">this SO answer</a> and it makes sense so @Column(unique = true) makes the constraint on the table but doesn't enforce it.</p>
  
  <p>So the question becomes how to create a @Unique annotation that checks with the database and returns a error message into BindingResult on POST handler.</p>
  
  <p>An example would be great.</p>
  
  <p><strong>UPDATE</strong></p>
  
  <p>I tried the following way to make a custom validator:</p>
  
  <p>The objects (note I have added @valid to get the validator messages to navigate up to BindingResult)</p>
  
  <p><strong>Person.java</strong></p>
  
  <pre><code>@Entity
  public class Person {
  public Person() {}
  
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
  // other stuff
  @UniqueNid
  private BigInteger nid;
  </code></pre>
  
  <p><strong>EpisodePerson.java</strong>  </p>
  
  <pre><code>@Entity
  public class EpisodePerson {
  public EpisodePerson(){};
  
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
  
  @ManyToOne
  @Valid
  private Person person;
  </code></pre>
  
  <p><strong>EpisodeViewModel (DTO)</strong></p>
  
  <pre><code>public class EpisodeViewModel {
  
  @Valid
  private Episode episode = new Episode();
  @Valid
  private List&lt;EpisodePerson&gt; persons = new ArrayList&lt;&gt;();
  </code></pre>
  
  <p><strong>UniqueNid.java</strong></p>
  
  <pre><code>@Documented
  @Target({ElementType.METHOD, ElementType.FIELD})
  @Retention(RetentionPolicy.RUNTIME)
  @Constraint(validatedBy = UniqueNiaValidator.class)
  public @interface UniqueNid {
  
  String message() default "{Duplicate ID}";
  Class&lt;?&gt;[] groups() default {};
  Class&lt;? extends Payload&gt;[] payload() default {};
  }
  </code></pre>
  
  <p><strong>UniqueNidValidator.java</strong></p>
  
  <pre><code>public class UniqueNidValidator implements ConstraintValidator&lt;UniqueNid, BigInteger&gt; {
  public UniqueNidValidator(){};
  
  private PersonRepository personRepository;
  
  @Autowired
  public void setPersonRepository(PersonRepository personRepository) {this.personRepository = personRepository;}
  
  public UniqueNidValidator(PersonRepository personRepository) {
      this.personRepository = personRepository;
  }
  
  @Override
  public void initialize(UniqueNid constraint) {
  }
  
  @Override
  public boolean isValid(BigInteger nid, ConstraintValidatorContext context) {
      return nid != null &amp;&amp; personRepository.existsByNid(nid);
  }
  }
  </code></pre>
  
  <p><strong>PersonRepository.java</strong></p>
  
  <pre><code>...
      Boolean existsByNid(BigInteger nid);
  ...
  </code></pre>
  
  <p><strong>Application.java</strong></p>
  
  <pre><code>@SpringBootApplication
  @EnableAutoConfiguration(exclude = { org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration.class })
  
  public class Demo3Application extends SpringBootServletInitializer {
  
  @Override
  protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
      return application.sources(WebApplicationInitializer.class);
  }
  
  public static void main(String[] args) {
      SpringApplication.run(Demo3Application.class, args);
  }
  
  @Bean
  public javax.validation.Validator localValidatorFactoryBean() {
      return new LocalValidatorFactoryBean();
  }
  }
  </code></pre>
  
  <p>When I go to submit a person I get :</p>
  
  <p><strong>Stack Trace (abbreviated)</strong></p>
  
  <pre><code>java.lang.NullPointerException: null
  at com.example.validators.UniqueNidValidator.isValid(UniqueNidValidator.java:31) ~[main/:na]
  </code></pre>
  
  <p><strong>UPDATE 2</strong></p>
  
  <p>I have also tried this configuration</p>
  
  <pre><code>public class UniqueNidValidator implements ConstraintValidator&lt;UniqueNid, BigInteger&gt; {
  
      public UniqueNidValidator(){};
  
      private PersonRepository personRepository;
  
      public UniqueNidValidator(PersonRepository personRepository) {
          this.personRepository = personRepository;
      }
  
      @Override
      public void initialize(UniqueNid constraint) {
      }
  
      @Override
      public boolean isValid(BigInteger nid, ConstraintValidatorContext context) {
          System.out.println("About to check " +nid.toString());
          System.out.println("person repo " +personRepository.toString() );
          return personRepository.existsByNid(nid);
      }
  }
  </code></pre>
  
  <p>which gives: </p>
  
  <pre><code>java.lang.NullPointerException: null
  at com.example.validators.UniqueNiaValidator.isValid(UniqueNiaValidator.java:29) ~[main/:na]
  </code></pre>
  
  <p>When I try to print the repo to console.</p>