18

Let's assume that I have a form where I might submit username(@NaturalId) and password for a new user.

I would like to add the user with a unique username. How can I use @Valid annotations to validate this constraint? And if username is not unique how can I display this information in jsp via <form:error/>?

Paulo Merson
  • 13,270
  • 8
  • 79
  • 72
user902691
  • 1,149
  • 4
  • 20
  • 46

4 Answers4

29

AFAIK there isn't an annotation to do this. You have two options

One, create a custom validator annotation. Here is a very good example. Make a call to your DAO class and check the availability in the validator implementation

    public boolean isValid(String object, ConstraintValidatorContext constraintContext) {

    return userDAO.userNameAvailable(object); //some method to check username availability
    }

OR

Set unique = true on your property in your entity class.

    @Column(unique = true)
    private String userName;

But this will not work with @valid, instead throw an exception on persistence. You have to use an appropriate logic to handle that.

The first solution isn't fool proof. Check this answer on SO.

The second will will never fail.

UPDATE

As NimChimpsky commented, using both together will be a concrete solution.

mavroprovato
  • 8,023
  • 5
  • 37
  • 52
shazinltc
  • 3,616
  • 7
  • 34
  • 49
  • 4
    I'd recommend using both methods – NimChimpsky Jun 14 '13 at 09:55
  • 1
    Well, after digging a bit I feel that the second one is better :) It will never fail unlike the first one. – shazinltc Jun 14 '13 at 13:17
  • 1
    um, well that relies on exception handling for when a user inputs a pre existing username, I woul dvalidate user input before trying to persist – NimChimpsky Jun 14 '13 at 13:23
  • 1
    what if there is a concurrent transaction with the same username?? – shazinltc Jun 14 '13 at 13:28
  • 2
    thats is very unlikely, but it is why I said both methods should used. The column shoul dbe unique, but that does not stop you vaidating input. – NimChimpsky Jun 14 '13 at 13:30
  • How solve the problem of the update of object? The userDAO.userNameAvailable(object) would return false. I didn't find so far a smart solution if the validation annotation is on the String field username. In fact in this way I cannot get the id of the object and check if it's an update (ok) or a new insert (ko). thanks – drenda Oct 02 '17 at 20:58
4

JSR-303 does not support what you want (something like a @Unique constraint). You have to write you own validator. How can this be done is explained here: https://community.jboss.org/wiki/AccessingtheHibernateSessionwithinaConstraintValidator

But before doing that make sure you read this answer: https://stackoverflow.com/a/3499111/1981720

And this sentence from the previous article:

The reason @Unique is not part of the built-in constraints is the fact that accessing the Session/EntityManager during a valiation is opening yourself up for potenital phantom reads.

Community
  • 1
  • 1
lunr
  • 5,159
  • 4
  • 31
  • 47
1

You can use UserDetailsService prepared spring class, extend and customize it :

@Service
public class LoginDetailsServiceImpl implements UserDetailsService, Serializable {

    @Autowired
    LoginService loginService;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        if (username == "" || username.isEmpty()) {
            throw new UsernameNotFoundException(String.format("User %s is invalid!", username));
        }
        Login login = loginService.find(username);
        if (login == null) {
            throw new UsernameNotFoundException(String.format("User %s does not exist!", username));
        }
        if (!loginService.scheduleChecking(login.getScheduled())) {
            throw new UsernameNotFoundException(String.format("User %s is not authorized this time!", username));
        }
      //....
Pasha
  • 1,534
  • 15
  • 27
0

I think there is a way to find a Unique User name. You Have to use Native Query to perform the Particular Task.

You have to perform this query on your repository interface

@Query(value = "SELECT * FROM customers_details WHERE username = :username , nativeQuery = true)
public List findEmaiList(@Param("username ") String username , @Param("id") Long id);

You can get similar data from the query and pass validation whatever you want. you can also create a separate Unique API for your convenience. You can also find different Unique parameters like Email or Mobile using this query